Я почувствовал, что задача Task.Delay()
и CancellationTokenSource
в других ответах довольно много для моего варианта использования в тесном сетевом цикле.
И хотя Создание задания Джо Хоага.Метод TimeoutAfter в блогах MSDN был вдохновляющим, я немного устал от использования TimeoutException
для управления потоком по той же причине, что и выше, потому что тайм-ауты ожидаются чаще, чем нет.
Так что я пошел сэто, что также обрабатывает оптимизации, упомянутые в блоге:
public static async Task<bool> BeforeTimeout(this Task task, int millisecondsTimeout)
{
if (task.IsCompleted) return true;
if (millisecondsTimeout == 0) return false;
if (millisecondsTimeout == Timeout.Infinite)
{
await Task.WhenAll(task);
return true;
}
var tcs = new TaskCompletionSource<object>();
using (var timer = new Timer(state => ((TaskCompletionSource<object>)state).TrySetCanceled(), tcs,
millisecondsTimeout, Timeout.Infinite))
{
return await Task.WhenAny(task, tcs.Task) == task;
}
}
Пример использования таков:
var receivingTask = conn.ReceiveAsync(ct);
while (!await receivingTask.BeforeTimeout(keepAliveMilliseconds))
{
// Send keep-alive
}
// Read and do something with data
var data = await receivingTask;