Почему нам нужно "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
, как в исходном стандартном коде?
Ответы
Ответ 1
Ok. Я думаю, что следующая статья отвечает на мой вопрос: 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
материализоваться в нить для параллельной оценки.
Ответ 2
a `par` b `par` a+b
будет оценивать a и b параллельно и возвращает a + b, да.
Тем не менее, pseq there обеспечивает как a, так и b оцениваются до того, как a + b.
Подробнее об этой теме см. эту ссылку.
Ответ 3
a `par` b `par` a+b
создает искры как для a
, так и для b
, но a+b
достигается немедленно, так что одна из искр будет fizzle (т.е. оценивается в основном потоке). Проблема с этим - эффективность, поскольку мы создали ненужную искру. Если вы используете это для реализации параллельного деления и покорения, тогда накладные расходы будут ограничивать ваше ускорение.
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
, и мы не создали ненужных искр.