Какие библиотеки следует использовать для улучшения потоковой обработки OCaml?

Я задал родственный вопрос до того, почему потоки OCaml считаются "недостаточно"?

Независимо от того, как "плохой" ocaml threading, я замечаю, что некоторые библиотеки говорят, что они могут делать настоящие потоки.

Например, сходница

Lwt предлагает новую альтернативу. Он обеспечивает очень легкие совлокальные потоки; "запуск" потока - очень быстрая операция, для него не требуется новый стек, новый процесс или что-то еще. Более того, коммутаторы контекста очень быстрые. На самом деле, так просто, что мы запустим поток для каждого системного вызова. И составление совлокальных потоков позволит нам писать высокоасинхронные программы.

Также Jane Street aync_core также предоставляет похожие вещи, если я прав.


Но я совершенно смущен. Lwt ли Lwt или aync_core потоки, такие как Java threading?

Если я их использую, могу ли я использовать несколько процессоров?

Каким образом можно получить "реальную поточную" (как на Java) в OCaml?


редактировать

Я все еще смущен.

Позвольте мне добавить сценарий:

У меня есть сервер (16 cpu cores) и серверное приложение.

Что делает серверное приложение:

  • Он слушает запросы
  • Для каждого запроса он запускает вычислительную задачу (скажем, стоит 2 минуты, чтобы закончить)
  • Когда каждая задача заканчивается, задача будет либо вернуть результат обратно в основную, либо просто отправить результат обратно клиенту непосредственно

На Java это очень просто. Я создаю пул потоков, затем для каждого запроса я создаю поток в этом пуле. этот поток будет выполнять вычислительную задачу. Это зрелое Java, и оно может использовать 16 ядер процессора. Я прав?

Поэтому мой вопрос: могу ли я сделать то же самое в OCaml?

Ответ 1

Пример параллелизированного сервера, который вы цитируете, является одной из тех проблемных проблем, которые хорошо решены с помощью простой многопроцессорной модели с использованием fork. Это было сделано в OCaml на протяжении десятилетий, и да, вы будете почти линейным ускорением, используя все ядра вашей машины, если вам нужно.

Для этого, используя простые примитивы стандартной библиотеки, см. Эту главу онлайн-книги "Системное программирование Unix в OCaml" (впервые выпущен в 2003 году) и/или эту главу онлайн-книги "Разработка приложений с OCaml" (сначала выпущен в 2000 году).

Вы также можете использовать библиотеки более высокого уровня, такие как библиотеку Gerd Stolpmann OCamlnet, упомянутую rafix, которая предоставляет множество материалов из прямого помощника для обычного дизайна клиент/сервер, в библиотеки многопроцессорных коммуникаций более низкого уровня; см. документацию.

Библиотека Parmap также интересна, но, возможно, для немного другого варианта использования (более того, у вас есть большой массив данных, доступных одновременно, которые вы хотите обрабатывать с помощью одной и той же функции параллельно): переходная замена из Array.map или List.map (или fold), который распараллеливает вычисления.

Ответ 2

Самое близкое, что вы найдете в реальной (превентивной) потоковой передаче, - это встроенная библиотека потоков. Под этим я имею в виду, что ваша модель программирования будет такой же, но с двумя важными отличиями:

  • Собственные потоки OCaml не такие легкие, как Java.
  • За один раз выполняется только один поток, поэтому вы не можете использовать несколько процессов.

Это делает потоки OCaml довольно плохим решением для параллелизма или параллелизма, поэтому в целом люди избегают их использования. Но у них все еще есть свои возможности.

Lwt и Async очень похожи и дают вам другой вкус резьбы - кооперативный стиль. Кооперативные потоки отличаются от превентивных в факте, что переключение между потоками явственно в коде, а блокирующие вызовы всегда очевидны из сигнатуры типа. Предоставляемые кооперативные потоки очень дешевы, так что они очень хорошо подходят для параллелизма, но снова не помогут вам с параллельными (из-за ограничений OCaml runtime).

См. Это для хорошего ознакомления с совместной резьбой: http://janestreet.github.io/guide-async.html

EDIT: для вашего конкретного сценария я бы использовал Parmap, если задачи настолько интенсивны в вычислительной мере, как в вашем примере, тогда накладные расходы на запуск процессов из parmap должны быть незначительными.