F #: избегать состояния гонки при вызове Task.WhenAny? - PullRequest
1 голос
/ 19 октября 2019

Итак, после небольшой работы с моделью F # Async, я думаю, что обернулся вокруг нее и ее различий с моделью C # Task. Одна из вещей, которые мне действительно нравятся в том, как они взаимодействуют, это Async.AwaitTask:

...
public Task<int> SomeCsharpApiAsync() {
    ...
}
...
let someFsharpAsyncCode = async {
    let! someResult = Async.AwaitTask (SomeClass.SomeCsharpApiAsync())
    return someResult
}

. С помощью приведенного выше кода строка, вызывающая AwaitTask, не только ожидает выполнения задачи, но и назначает еерезультат для переменной someResult в операции, которую я считаю атомарной. Очень аккуратно!

Однако у меня возникла проблема с достижением того же (атомарность, отсутствие условий гонки) при использовании Task.WhenAny:

...
public Task<int> SomeCsharpApiAsync(string someParam) {
    ...
}
...
let someFsharpAsyncCode = async {
    let task1 = SomeClass.SomeCsharpApiAsync "foo"
    let task2 = SomeClass.SomeCsharpApiAsync "bar"
    let! fastestTask = Async.AwaitTask (Task.WhenAny([task1;task2]))
    return fastestTask.Result
}

Проблема сПриведенный выше код заключается в том, что операция AwaitTask возвращает задачу (самую быструю), а не результат, так что это дополнительный уровень косвенности, который я решаю, вызвав .Result позже. Но я обнаружил проблемы по этому поводу, виновником которых, по-моему, являются условия гонки: самая быстрая задача может иметь какой-то результат в тот момент, но при получении результата ее можно было бы запросить (отменено) отмену задания задачи! Или самая быстрая задача была быстрее, потому что на самом деле она была отменена быстрее? Я не уверен, и я немного растерялся, как выяснить, что здесь происходит.

Может быть, я смогу полностью избежать этой проблемы, используя F # альтернативу Task.WhenAny?

.

1 Ответ

0 голосов
/ 19 октября 2019

Посмотрите, может ли эта реализация Async.WhenAny решить вашу проблему: https://github.com/tpetricek/TryJoinads/blob/master/src/FSharp.Joinads/Async.fs#L9

См. Также этот блог: http://tomasp.net/blog/joinads-async-implement.aspx/

Этот пример очень похож на ваш код, но, возможно,есть небольшая разница: https://github.com/microsoft/fsharplu/blob/master/FSharpLu/Async.fs#L59

А вот еще один краткий пример с другой целью, но он все еще может быть полезен: http://www.fssnip.net/hx/title/AsyncAwaitTask-with-timeouts

...