Итак, после небольшой работы с моделью 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
?
.