Зачем нам нужен 'seq' или 'pseq' с 'par' в Haskell?
Я пытаюсь понять, почему нам нужны все части стандартного примера кода:
a `par` b `pseq` a+b
Почему следующего не будет достаточно?
a `par` b `par` a+b
Вышеупомянутое выражение кажется очень описательным: попробуйте оценить оба a
а также b
параллельно, и вернуть результат a+b
, Причина только в эффективности: вторая версия будет зажигаться дважды, а не один раз?
Как насчет следующей, более краткой версии?
a `par` a+b
Зачем нам нужно убедиться b
оценивается раньше a+b
как в оригинальном, стандартном коде?
3 ответа
Хорошо. Я думаю, что следующая статья отвечает на мой вопрос: http://community.haskell.org/~simonmar/papers/threadscope.pdf
В итоге проблема с
a `par` b `par` a+b
а также
a `par` a+b
это отсутствие упорядоченности оценки. В обеих версиях основной поток начинает работать a
(или иногда b
) немедленно, что приводит к немедленному "исчезновению" искр, поскольку больше нет необходимости запускать поток, чтобы оценить, что основной поток уже начал оценивать.
Оригинальная версия
a `par` b `pseq` a+b
обеспечивает работу основного потока b
до a+b
(иначе бы начал оценивать a
вместо этого), таким образом, давая шанс для искры a
материализовать в поток для параллельной оценки.
a `par` b `par` a+b
будет оценивать a и b параллельно и возвращает a+b, да.
Тем не менее, pseq гарантирует, что a и b будут оценены перед тем, как a+b будет.
Смотрите эту ссылку для более подробной информации по этой теме.
a `par` b `par` a+b
создает искры для обоих a
а также b
, но a+b
достигается немедленно, так что одна из искр замирает (т. е. оценивается в основном потоке). Проблема с этим - эффективность, поскольку мы создали ненужную искру. Если вы используете это для реализации параллельного разделения и завоевания, то накладные расходы ограничат ваше ускорение.
a `par` a+b
кажется лучше, потому что он создает только одну искру. Тем не менее, пытаясь оценить a
до b
зажжет искру для a
, и в качестве b
не имеет искры, это приведет к последовательной оценке a+b
, Переключение заказа на b+a
решит эту проблему, но как код это не навязывает порядок, и Haskell все еще может оценить это как a+b
,
Итак, мы делаем a `par` b `pseq` a+b
провести оценку b
в главном потоке, прежде чем мы попытаемся оценить a+b
, Это дает a
Искра шанс материализоваться, прежде чем мы попробуем оценить a+b
и мы не создали ненужных искр.