2010-11-05 5 views
4

Я хотел бы запустить некоторый асинхронные рабочий процесс, а затем ждать его, чтобы закончить перед печатью некоторых результатов, например:Как ждать асинхронных закончить

let dowork n = 
    async { 
     do printfn "work %d" n 
    } 

let creatework() = 
    async { 
     for x in [1..5] do 
      Async.Start(dowork x) 
    } 

Async.RunSynchronously(creatework())  
printfn "finished" 

, когда я запускаю это, я хочу, чтобы весь DoWork звонков до завершения печати «закончено». Однако я получаю результаты, как это:

работы 2 работа 3 работа 4 работа 5 закончил работа 1

Я попытался удалить асинхра из creatework(), но «закончил» печатаются перед асинхронными рабочими процессами выполняются.

В реальном dowork программа выполняет несколько операций ввода-вывода, поэтому я хочу дождаться, пока самый медленный закончен, прежде чем продолжить.

+0

Вы можете отслеживать, сколько из них завершено, и как только они будут завершены. Однако, вероятно, есть лучший подход, который я просто не могу придумать. –

+0

Следите, как? – yanta

+0

Не ждет асинк, чтобы закончить вид оксюморона? –

ответ

7

Ну, отвечая на мой собственный вопрос, кажется хромым, но это, похоже, работает. Кто-то придумать что-то лучше, чтобы я мог присудить им ответ :)

let dowork n = 
    async { 
     do printfn "work %d" n 
    } 

let creatework() = 
    [1..5] |> Seq.map dowork |> Async.Parallel |> Async.RunSynchronously 

creatework()  
printfn "finished" 

Это дает различные выходные, но «закончил» до сих пор всегда в последний раз ...

+2

Это правильный ответ. Исходный код вызова 'Async.Start' внутри блока асинхронизации был очень неидиоматичным. 'Async.Parallel' - это правильный путь для параллелизма fork-join. – Brian

+2

Крошечный рефакторинг: вместо 'Seq.map (fun x -> dowork x)' вы могли бы просто сделать 'Seq.map dowork'. –

+0

@Brian разъяснения @Greg хорошая точка - обновлено – yanta

1

я обнаружил, что это удобно использовать MailboxProcessor, чтобы убедиться, что все побочные эффекты (например, printfn) происходят в одном потоке. Используйте MailboxProcessor.PostAndReply (singleResult), чтобы возить результаты работы (будь то строки для печати) в один и тот же контекст синхронизации и предоставить другой тип сообщения, возвращающий агрегированные значения. Можно использовать объединение для типов этих сообщений.

Смежные вопросы