Позволять! выполняется в последовательности? - PullRequest
2 голосов
/ 04 октября 2010

У меня сложилось впечатление, что давай! в f # был достаточно умен, чтобы извинять последовательности назначений в параллели. Однако в следующем примере показано другое поведение: назначение a, b, c выполняется синхронно.

    let sleep sec =
        async
            {
                System.Threading.Thread.Sleep(sec * 1000)
                return sec
            }

    let bar = async 
                {
                    let! a = sleep 1
                    let! b = sleep 3
                    let! c = sleep 3
                    return a+b+c
                }

    let foo = Async.RunSynchronously(bar)
    printfn "%d" foo

Это так / должно быть?

И если я хочу выполнить a, b, c параллельно, я должен использовать Async.Parallell ... |> Async.RunSynchronously ... тогда?

Приведенный выше пример, конечно, бесполезен, реальный вариант использования - это что-то вроде запроса к БД и одновременного вызова некоторых веб-сервисов.

Ответы [ 2 ]

7 голосов
/ 04 октября 2010

Как отмечает Ричард, асинхронные рабочие процессы по-прежнему полностью последовательны. Я не думаю, что какие-либо проекты, пытающиеся выполнить полностью автоматическое распараллеливание, были полностью успешными, потому что это слишком сложно.

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

  • На основе задач вы можете запустить свои три задачи в фоновом режиме, а затем подождать, пока все они не будут выполнены (это, вероятно, то, что вы ожидали, поэтому вот как написать это явно):

    let bar = async  { 
      let! atask = sleep 1 |> Async.StartChild
      let! btask = sleep 3 |> Async.StartChild
      let! ctask = sleep 3 |> Async.StartChild
      let! a = atask
      let! b = btask
      let! c = ctask
      return a + b + c } 
    
  • Параллельная передача данных - если у вас есть несколько рабочих процессов одного типа, вы можете создать рабочий процесс, который запускает их все параллельно, используя Async.Parallel. Когда вы затем используете let!, он запускает все три задачи и ожидает их завершения:

    let bar = async  { 
      let! all = Async.Parallel [ sleep 1; sleep 3; sleep 3 ]
      return all.[0] + all.[1] + all.[2] } 
    

В статье Дона Сайма обсуждается различные шаблоны , основанные на асинхронных рабочих процессах, и вы можете найти исчерпывающий пример в примере финансовой панели управления

2 голосов
/ 04 октября 2010

let! в блоке async (или, точнее, "вычислительном выражении") асинхронно выполняет выражение , но блок в целом все еще выполняется линейно.Это преимущество async вычислительных выражений: значительно упрощает написание последовательности зависимых асинхронных операций, выполняя передачу для вас.

(Другие типы выражений вычислений предоставляют собственную семантику для let!yield!, и т.1018 * Вы неправильно поняли (вполне понятно).

...