Python中的异步函数调用

1 投票
2 回答
659 浏览
提问于 2025-04-29 19:05

在Python中,我想在一个类里创建一个异步方法,这个方法可以启动一个线程,而不会阻塞主线程。等这个新线程完成后,我想从那个函数/线程中返回一个值。

举个例子,这个类是用来从网页上获取一些信息的。我想在一个函数中进行并行处理,这个函数负责下载网页并返回一个对象。

class WebDown:
    def display(self, url):
        print 'display(): ' + content

    def download(self, url):
        thread = Thread(target=self.get_info)
        # thread join
        print 'download(): ' + content
        # return the info

    def get_info(self, url):
        # download page
        # retrieve info
        return info

if __name__ == '__main__':
    wd = WebDown()
    ret = wd.download('http://...')
    wd.display('http://...')

在这个例子中,我先调用download()来获取信息,然后再调用display()来打印其他信息。打印的输出应该是

display(): foo, bar, ....
download(): blue, red, ....
暂无标签

2 个回答

0

我会简单地使用request库和gevent库,结合使用grequests

import grequests
>>> urls = [
    'http://...',
    'http://...'
]
>>> rs = (grequests.get(u) for u in urls)
>>> grequests.map(rs)
[<Response [200]>, <Response [200]>]
1

在Python中,有一种写异步、不阻塞代码的方法,就是使用Python的Twisted库。Twisted不依赖于多线程,而是使用多进程。它提供了一种方便的方式来创建Deferred对象,并为这些对象添加回调和错误回调。你给出的例子在Twisted中看起来会是这样的,我使用了treq(Twisted请求)库,这让生成请求变得更快更简单:

from treq import get
from twisted.internet import reactor

class WebAsync(object):
    def download(self, url):
        request = get(url)
        request.addCallback(self.deliver_body)

    def deliver_body(self, response):
        deferred = response.text()
        deferred.addCallback(self.display)
        return deferred

    def display(self, response_body):
        print response_body
        reactor.stop()

if __name__ == "__main__":
    web_client = WebAsync()
    web_client.download("http://httpbin.org/html")
    reactor.run()

这里的'download'和'deliver_body'方法都会返回一种叫做deferreds的东西,你可以给它们添加回调函数,这些函数会在结果可用时执行。

撰写回答