Scrapy Item Pipelines 中 Python 集合的线程安全问题(使用 Twisted 实现并发)
Threadsafety question for Python collections in Scrapy Item Pipelines (using Twisted for concurrency)
Scrapy 有一个概念Item Pipelines that concurrently process (via Twisted) items returned from a Scrapy Spider. The following code example is provided for filtering duplicate items (code copied below). How is it that the set
can be used safely by concurrent calls to process_item
? It seems that Scrapy invokes item pipelines here。
from scrapy.exceptions import DropItem
class DuplicatesPipeline:
def __init__(self):
self.ids_seen = set()
def process_item(self, item, spider):
if item['id'] in self.ids_seen:
raise DropItem("Duplicate item found: %s" % item)
else:
self.ids_seen.add(item['id'])
return item
Twisted 和 Scrapy 主要是单线程的。它们不是抢占式多线程,而是通过协作式多任务处理来提供并发性。在协作式多任务系统中,没有抢占。这意味着像上面的 process_item
这样的函数是完全安全的,可以假设 self.ids_seen
在它的第一行和倒数第二行之间不会改变。只有这个process_item
方法是运行ning。在 process_item
合作放弃控制之前,无法进行其他工作。它通过引发异常或 return 值来实现。发生这种情况时,控制 returns 到它的调用者(或任何最近的 except
处理程序)。然后该代码到达 运行 直到它决定放弃控制,等等。最终控制 return 一直到 Twisted reactor
,它通过调用一些应用程序方法来选择另一个事件来服务。然后重复该过程。
Scrapy 有一个概念Item Pipelines that concurrently process (via Twisted) items returned from a Scrapy Spider. The following code example is provided for filtering duplicate items (code copied below). How is it that the set
can be used safely by concurrent calls to process_item
? It seems that Scrapy invokes item pipelines here。
from scrapy.exceptions import DropItem
class DuplicatesPipeline:
def __init__(self):
self.ids_seen = set()
def process_item(self, item, spider):
if item['id'] in self.ids_seen:
raise DropItem("Duplicate item found: %s" % item)
else:
self.ids_seen.add(item['id'])
return item
Twisted 和 Scrapy 主要是单线程的。它们不是抢占式多线程,而是通过协作式多任务处理来提供并发性。在协作式多任务系统中,没有抢占。这意味着像上面的 process_item
这样的函数是完全安全的,可以假设 self.ids_seen
在它的第一行和倒数第二行之间不会改变。只有这个process_item
方法是运行ning。在 process_item
合作放弃控制之前,无法进行其他工作。它通过引发异常或 return 值来实现。发生这种情况时,控制 returns 到它的调用者(或任何最近的 except
处理程序)。然后该代码到达 运行 直到它决定放弃控制,等等。最终控制 return 一直到 Twisted reactor
,它通过调用一些应用程序方法来选择另一个事件来服务。然后重复该过程。