Ответ 1
В целом часто бывает лучше избегать новых задач, если вы уже работаете с основанными на задачах методами. Цепочки задач вместо блокировки явно уменьшат накладные расходы системы, так как она не будет поддерживать ожидание потока ThreadPool.
Как говорится, часто проще просто блокировать, как вы делаете.
Обратите внимание, что С# 5 делает это намного проще, предоставляя API, который дает вам лучшее из обоих:
public async Task<string> GetSomeData(CancellationToken token)
{
token.ThrowIfCancellationRequested();
var initialData = await SomeOtherMethodWhichReturnsTask(token);
string result = await initialData.MethodWhichAlsoReturnsTask(token);
return result;
};
Изменить после обновления:
Учитывая новый код, нет простого способа связать его с помощью ContinueWith
. Есть несколько вариантов. Вы можете использовать Unwrap для преобразования созданного Task<Task<string>>
, то есть:
public Task<string> GetSomeData(CancellationToken token)
{
Task<Task<string>> task = GetSomeInteger(token)
.ContinueWith(t =>
{
return GetSomeString(t.Result, token);
}, token);
return task.Unwrap();
}
В качестве альтернативы вы можете легко отрегулировать себя с помощью TaskCompletionSource<T>
:
public Task<string> GetSomeData(CancellationToken token)
{
var tcs = new TaskCompletionSource<string>();
Task<int> task1 = GetSomeInteger(token);
Task<Task<string>> task2 = task1.ContinueWith(t => GetSomeString(t.Result, token));
task2.ContinueWith(t => tcs.SetResult(t.Result.Result));
return tcs.Task;
}
Это позволяет всему процессу работать без создания новой задачи (которая связывает поток threadpool) и никогда не блокирует.
Обратите внимание, что вы, вероятно, захотите добавить продолжения при аннулировании и использовать tcs.SetCancelled, когда была запрошена отмена.