Вопрос о безопасности потоков для коллекций Python в конвейерах элементов Scrapy (с использованием Twisted для параллелизма)

В Scrapy есть понятие конвейеров элементов, которые одновременно обрабатывать (через Twisted) элементы, возвращенные из Scrapy Паук. Следующий пример кода предназначен для фильтрации повторяющихся элементов (код скопирован ниже). Как получается, что set можно безопасно использовать для одновременных вызовов process_item? Похоже, что Scrapy вызывает конвейеры элементов здесь .

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

person Jessica    schedule 29.05.2020    source источник


Ответы (1)


Twisted и Scrapy в основном однопоточные. Вместо упреждающей многопоточности они обеспечивают параллелизм посредством совместной многозадачности. В кооперативной многозадачной системе нет вытеснения. Это означает, что функция, подобная process_item выше, совершенно безопасно предполагает, что self.ids_seen не изменится между первой и предпоследней строками. Работает только этот метод process_item. Никакая другая работа не может быть выполнена до тех пор, пока process_item совместно не откажется от контроля. Он делает это, вызывая исключение или возвращая значение. Когда это происходит, управление возвращается вызывающей стороне (или какому-либо ближайшему обработчику except). Затем этот код запускается до тех пор, пока не решит отказаться от управления, и так далее. В конце концов управление полностью возвращается к Twisted reactor, который выбирает другое событие для обслуживания, вызывая какой-либо метод приложения. Затем процесс повторяется.

person Jean-Paul Calderone    schedule 29.05.2020