繁体   English   中英

同时在python中运行多个线程 - 这可能吗?

[英]running multiple threads in python, simultaneously - is it possible?

我正在编写一个应该多次获取URL的小爬虫,我希望所有的线程同时运行(同时)。

我写了一小段应该这样做的代码。

import thread
from urllib2 import Request, urlopen, URLError, HTTPError


def getPAGE(FetchAddress):
    attempts = 0
    while attempts < 2:
        req = Request(FetchAddress, None)
        try:
            response = urlopen(req, timeout = 8) #fetching the url
            print "fetched url %s" % FetchAddress
        except HTTPError, e:
            print 'The server didn\'t do the request.'
            print 'Error code: ', str(e.code) + "  address: " + FetchAddress
            time.sleep(4)
            attempts += 1
        except URLError, e:
            print 'Failed to reach the server.'
            print 'Reason: ', str(e.reason) + "  address: " + FetchAddress
            time.sleep(4)
            attempts += 1
        except Exception, e:
            print 'Something bad happened in gatPAGE.'
            print 'Reason: ', str(e.reason) + "  address: " + FetchAddress
            time.sleep(4)
            attempts += 1
        else:
            try:
                return response.read()
            except:
                "there was an error with response.read()"
                return None
    return None

url = ("http://www.domain.com",)

for i in range(1,50):
    thread.start_new_thread(getPAGE, url)

从apache日志来看,似乎线程并不是同时运行,请求之间有一点差距,它几乎检测不到但我可以看到线程并不是真正的并行。

我读过GIL,有没有办法绕过它而不用调用C \\ C ++代码? 我真的不明白GIL如何实现线程化? python基本上解释了下一个线程一旦完成前一个线程?

谢谢。

正如您所指出的,GIL经常阻止Python线程并行运行。

然而,情况并非总是如此。 I / O绑定代码是一个例外。 当一个线程正在等待I / O请求完成时,它通常会在进入等待之前释放GIL。 这意味着其他线程可以在此期间取得进展。

但是,一般而言,当需要真正的并行性时, multiprocessing是更安全的选择。

我读过GIL,有没有办法绕过它而不用调用C \\ C ++代码?

并不是的。 通过ctypes调用的函数将在这些调用期间释放GIL。 执行阻塞I / O的函数也会释放它。 还有其他类似的情况,但它们总是涉及主Python解释器循环之外的代码。 你不能放弃Python代码中的GIL。

您可以使用这样的方法来创建所有线程,让它们等待条件对象,然后让它们开始“ 同时 ”获取URL:

#!/usr/bin/env python
import threading
import datetime
import urllib2

allgo = threading.Condition()

class ThreadClass(threading.Thread):
    def run(self):
        allgo.acquire()
        allgo.wait()
        allgo.release()
        print "%s at %s\n" % (self.getName(), datetime.datetime.now())
        url = urllib2.urlopen("http://www.ibm.com")

for i in range(50):
    t = ThreadClass()
    t.start()

allgo.acquire()
allgo.notify_all()
allgo.release()

这会让你更接近于同时发生所有提取, 但是

  • 离开计算机的网络数据包将按顺序通过以太网线传输,而不是同时传递,
  • 即使您的计算机上有16个以上的核心,您的计算机和Web主机之间的某些路由器,网桥,调制解调器或其他设备也可能拥有较少的核心,并且可能会对您的请求进行序列化,
  • 您从中获取内容的Web服务器将使用accept()调用来响应您的请求。 对于正确的行为,使用服务器全局锁实现,以确保只有一个服务器进程/线程响应您的查询。 即使您的某些请求同时到达服务器,也会导致某些序列化。

您可能会在更大程度上获得重叠请求(即其他人在完成之前开始),但您永远不会在服务器上同时启动所有请求。

如果您使用Jython或IronPython(以及未来的PyPy)运行代码,它将并行运行

你还可以看看像pypy的未来,我们将拥有软件过渡记忆(从而废除GIL)这一切只是研究和知识分子嘲笑,但它可能会成长为一个大的东西。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM