有没有办法在不同的线程上运行python而不会有崩溃的风险?

时间:2012-09-01 14:55:03

标签: python windows urllib cpython python-multithreading

我有一个程序在无限循环中运行大量的urllib请求,这使我的程序真的很慢,所以我尝试将它们作为线程。 Urllib在套接字模块中使用cpython内部深处,因此正在创建的线程只是加起来并且什么也不做,因为python的GIL会阻止两个cpython命令同时在diffident线程中执行。我使用Python 2.5运行Windows XP,因此我无法使用多进程模块。我试着查看子进程模块,看看是否有办法以某种方式在子进程中执行python代码,但没有。如果有人可以通过多进程中的函数创建python子进程,那就太棒了。

另外,我宁愿不下载外部模块,但我愿意。

编辑:以下是我当前程序中一些代码的示例。

    url = "http://example.com/upload_image.php?username=Test&password=test"
    url = urllib.urlopen(url, data=urllib.urlencode({"Image": raw_image_data})).read()
    if url.strip().replace("\n", "") != "":
        print url

我做了一个测试,结果发现urllib2的urlopen与Request对象并没有仍然是慢或慢。我创建了自己的自定义时间模块,上面大概需要0.5-2秒,这对我的程序来说非常糟糕。

2 个答案:

答案 0 :(得分:1)

  

Urllib在套接字模块中深入使用cpython,所以线程   正在创建的只是加起来并且什么也不做因为python的GIL   防止两个cpython命令在diffident中执行   线程在同一时间。

错误。虽然这是一种常见的误解。 CPython可以并且确实为IO操作释放GIL(查看socketmodule.c中的所有Py_BEGIN_ALLOW_THREADS)。当一个线程等待IO完成其他线程可以做一些工作。如果urllib调用是您脚本中的瓶颈,那么线程可能是可接受的解决方案之一。

  

我使用Python 2.5运行Windows XP,因此无法使用多进程模块。

您可以安装Python 2.6或更高版本,或者必须使用Python 2.5;您可以单独安装multiprocessing

  

我创建了自己的自定义时间模块,上面大概需要0.5-2秒,这对我的程序来说非常糟糕。

urllib2.urlopen('http://example.com...).read()的性能主要取决于外部因素,如DNS,网络延迟/带宽,example.com服务器本身的性能。

以下是使用threadingurllib2

的示例脚本
import urllib2
from Queue import Queue
from threading import Thread

def check(queue):
    """Check /n url."""
    opener = urllib2.build_opener() # if you use install_opener in other threads
    for n in iter(queue.get, None):
        try:
            data = opener.open('http://localhost:8888/%d' % (n,)).read()
        except IOError, e:
            print("error /%d reason %s" % (n, e))
        else:
            "check data here"

def main():
    nurls, nthreads = 10000, 10

    # spawn threads
    queue = Queue()
    threads = [Thread(target=check, args=(queue,)) for _ in xrange(nthreads)]
    for t in threads:
        t.daemon = True # die if program exits
        t.start()

    # provide some work
    for n in xrange(nurls): queue.put_nowait(n)
    # signal the end
    for _ in threads: queue.put(None)
    # wait for completion
    for t in threads: t.join()

if __name__=="__main__":
   main()

要将其转换为多处理脚本,只需使用不同的导入,您的程序将使用多个进程:

from multiprocessing import Queue
from multiprocessing import Process as Thread

# the rest of the script is the same

答案 1 :(得分:0)

如果你想要多线程,Jython可以是一个选项,因为它没有GIL。

我赞同@ Jan-Philip和@Piotr。你在用urllib做什么?