Lwt.async() не работает должным образом

Я разрабатываю веб-сервис в Ocaml поверх MirageOS (Unix), и в данный момент у меня проблемы с Lwt.async(). В документации Lwt указано следующее:

val async : (unit -> 'a t) -> unit

async f запускает поток, не дожидаясь результата. В случае сбоя (сейчас или позже) исключение передается Lwt.​async_exception_hook.

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

Поэтому я сразу же посчитал Lwt.async хорошим кандидатом для запуска некоторых тестов и проверки того, что на самом деле выполнение является асинхронным. К сожалению, это не работает, как ожидалось. Мой код следующий:

let http_callback conn_id req _body =
  Lwt.return(Uri.path (Cohttp.Request.uri req))
  >>= function
     | "/tester" -> Cohttp_lwt_body.to_string _body >>= fun res -> 
        log_lwt ~inject:(fun f -> f "Testing") >>= fun () ->
        Lwt.async(fun () -> TEST.start 100 res !listOfIP);
        H.respond_string ~status:`OK ~body:("DONE") ()
  in
     let spec = H.make ~callback:http_callback () in
     CON.listen conduit (`TCP 8080) (H.listen spec)

Для ясности, TEST.start выполняет серию многопоточных операций. Я предполагаю, что на самом деле не имеет значения, что делает функция внутри Lwt.async, учитывая, что все, что возвращает/делает, следует игнорировать. Я ошибся?

В конце концов, мой вопрос: почему на самом деле клиент должен ждать, пока поток получит ответ OK? С асинхронностью или без нее поведение в основном одинаковое.


person Vittorio Cozzolino    schedule 05.12.2016    source источник


Ответы (1)


Управление переключится обратно на обработчик HTTP, только если асинхронный поток заблокируется в ожидании чего-либо. Если он просто использует ЦП на 100% до тех пор, пока он не будет выполнен, то асинхронный поток, вероятно, будет сначала выполняться до завершения. Попробуйте поставить сон в тестах, чтобы проверить.

person Thomas Leonard    schedule 05.12.2016
comment
Спасибо за ответ, попробую в ближайшее время. - person Vittorio Cozzolino; 05.12.2016
comment
Я полностью заменил фрагмент кода, вызываемый TEST.start, на Lwt.return(Unix.sleep 10), но результат точно такой же. Когда я запускаю curl -X POST --data something 10.0.0.2:8080/tester, консоль зависает и Я должен ждать 10 секунд, чтобы получить ответ. Я имею в виду, что если я вызову сон из вторичного потока, я действительно не ожидаю, что основной поток остановится. - person Vittorio Cozzolino; 06.12.2016
comment
Потоки LWT не являются вытесняющими. На самом деле это обещания. Попробуйте использовать Lwt_unix.sleep 10. вместо Lwt.return (Unix.sleep 10). - person antron; 06.12.2016
comment
Спасибо, теперь работает! Теперь мне нужно выяснить, есть ли способ исправить это без sleep. - person Vittorio Cozzolino; 06.12.2016
comment
Вы передали функцию async, которая обрабатывает обещание Lwt (ошибочно названное Lwt thread). Эта функция выполняется вместе с остальными вашими распознавателями обещаний Lwt в одном системном потоке в одном процессе OCaml. Таким образом, вам нужно избегать каких-либо блокирующих вызовов из Unix. или других модулей в любом месте вашей программы и использовать замену Lwt для всего. Они используют системные рабочие потоки в фоновом режиме (при необходимости) для разрешения различных обещаний Lwt в вашем основном системном потоке. Вы, наверное, уже видели Lwt_unix. - person antron; 06.12.2016