簡體   English   中英

如何在Scrapy / Twisted中使用線程,即如何在響應回調中執行異步調用阻塞代碼?

[英]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回調必須只返回NoneRequestBaseItem對象。

根據@ 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM