Подтвердить что ты не робот

Нужны ли пулы потоков для чистого кода Haskell?

В Real World Haskell, глава 28, транзакционная память программного обеспечения, разработана параллельная веб-ссылка. Он извлекает все ссылки на веб-странице и каждый раз обращается к ним с запросом HEAD, чтобы выяснить, активна ли ссылка. Для создания этой программы используется параллельный подход, и делается следующее утверждение:

Мы не можем просто создать один поток для каждого URL-адреса, потому что это может перегрузить либо наш процессор, либо наше сетевое соединение, если (как мы ожидаем) большинство ссылок являются живыми и отзывчивыми. Вместо этого мы используем фиксированное количество рабочих потоков, которые извлекают URL-адреса для загрузки из очереди.

Я не совсем понимаю, зачем нужен этот пул потоков вместо использования forkIO для каждой ссылки. AFAIK, среда исполнения Haskell поддерживает пул потоков и планирует их соответствующим образом, поэтому я не вижу перегрузки процессора. Кроме того, в обсуждении concurrency в списке рассылки Haskell я нашел следующее утверждение в том же направлении:

Одна парадигма, которая не имеет смысла в Haskell, - это рабочие потоки (поскольку RTS делает это для нас); вместо того, чтобы получать работника, вместо этого вместо forkIO.

Требуется ли только пул потоков для сетевой части или есть причина для процессора?

4b9b3361

Ответ 1

Основной проблемой, я думаю, является сетевая сторона. Если у вас есть 10 000 ссылок и forkIO для каждой ссылки, тогда у вас потенциально будет 10 000 сокетов, которые вы пытаетесь открыть сразу, что, в зависимости от конфигурации вашей ОС, вероятно, будет даже невозможным, гораздо менее эффективным.

Однако тот факт, что у нас есть зеленые потоки, которые "фактически" запланированы для нескольких потоков os (которые идеально подходят для отдельных ядер), не означает, что мы можем просто распределять работу произвольно без учета использования процессора. Проблема здесь заключается не столько в том, что планирование самого ЦП не будет обрабатываться для нас, а в том, что коммутаторы контекста (даже зеленые) будут стоить. Каждый поток, если он работает с разными данными, должен будет вытащить эти данные в процессор. Если есть достаточное количество данных, это означает вытягивание вещей из кэша процессора и из него. Даже отсутствует, это означает вытягивание вещей из кеша в регистры и т.д.

Даже если проблема тривиально параллельна, практически невозможно правильно разбить ее как можно меньше и попытаться сделать это "все сразу".