![](/img/trans.png)
[英]How to call async function in sync code and break async/await chain (i.e. how to wrap an async function in a sync function)
[英]How to use threading in Scrapy/Twisted, i.e. how to do async calls to blocking code in response callbacks?
我需要在Scrapy中运行一些多线程\\多处理工作(因为我有一些使用阻塞调用的库),并在完成之后将请求发送回Scrapy引擎。
我需要这样的东西:
def blocking_call(self, html):
# ....
# do some work in blocking call
return Request(url)
def parse(self, response):
return self.blocking_call(response.body)
我怎么能这样做? 我想我应该使用Twisted reactor和Deferred对象。 但是Scrapy parse
回调必须只返回None
或Request
或BaseItem
对象。
根据@ Jean-Paul Calderone的回答,我做了一些调查和测试,这是我发现的。
内部scrapy使用Twisted框架来管理请求/响应同步和异步调用。
Scrapy以异步方式生成请求 (爬网),但处理响应 (我们的自定义解析回调函数)是同步完成的。 因此,如果您在回调中有阻塞调用, 它将阻止整个引擎 。
希望这可以改变。 处理延迟响应回调结果时,如果Deferred对象返回其他Deferred对象,Twisted将处理大小写(twisted.internet.defer.Deferred source) 。 在这种情况下,Twisted会产生新的异步调用。
基本上,如果我们从响应回调中返回Deferred对象 ,这将改变响应回调调用从同步到异步的性质 。 为此,我们可以使用方法deferToThread ( 内部调用 deferToThreadPool(reactor, reactor.getThreadPool()...
- 在@ Jean-Paul Calderone代码示例中使用)。
工作代码示例是:
from twisted.internet.threads import deferToThread
from twisted.internet import reactor
class SpiderWithBlocking(...):
...
def parse(self, response):
return deferToThread(reactor, self.blocking_call, response.body)
def blocking_call(self, html):
# ....
# do some work in blocking call
return Request(url)
此外,只有回调可以返回Deferred对象,但start_requests
不能(scrapy逻辑)。
如果要在阻塞操作完成在其中一个reactor的线程池线程中运行后返回触发的Deferred
,请使用deferToThreadPool
:
from twisted.internet.threads import deferToThreadPool
from twisted.internet import reactor
...
def parse(self, response):
return deferToThreadPool(
reactor, reactor.getThreadPool(), self.blocking_call, response.body)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.