Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
using (cancellationToken.Register(() => tcs.TrySetCancelled()))
await tcs.Task;
WithCancellationWithCancellation тоже пишется проще.public static async Task<T> WithCancellation<T>(this Task<T> task, CancellationToken cancellationToken) {
await task.ContinueWith(_ => {}, cancellationToken, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
return await task;
}
_tcsDictionary.Remove(key) надо делать в блоке finally!await и тут тоже._tcsDictionary никак не защищен. Следует либо использовать специальный однопоточный планировщик задач (и добавить всюду проверки, что метод именно в этом потоке и выполняется) — либо заменить Dictionary на ConcurrentDictionaryа вот насчет 5го пункта я не совсем понимаю, какие проблемы могут возникнуть и в каких ситуациях, если будет использован простой Dictionary, а не Concurrent?А попробуйте — и увидите сами. Создайте 1000 потоков, которые будут сначала добавлять что-нибудь в словарь, а потом удалять обратно — и так много раз.
public static Task<T> WithCancellation<T>(this Task<T> task, CancellationToken token)
{
return task.ContinueWith(t => t.GetAwaiter().GetResult(), token);
}
That's reasonable. If you're planning to use this for real, you'd probably want a few tweaks:
1. First check task.IsCompleted, and if it's true, just return 'task' rather than doing a continuation.
2. Pass TaskScheduler.Default as the scheduler and TaskContinuationOptions.ExecuteSynchronously as the continuation options to the call to ContinueWith.
_tcs.Dictionary.Remove(key) нет никакого смысла проверять наличие этого ключа там. Во-первых, этот ключ там по логике программы всегда есть, а во-вторых Remove сама умеет делать эту проверку.SetResult надо использовать TrySetResult, особенно если вы последовали моему совету номер 1. В противном случае, если успеть отменить чтение, когда ключ уже получен из словаря, но SetResult еще не вызван — весь цикл чтения упадет с ошибкой.Tuple<string, int> в качестве ключа в словаре можно использовать непосредственно класс IPEndPoint. Это ничуть не усложнит код SendReceiveUdpAsync — но значительно упростит код цикла чтения._client.Send(msg, msg.Length, ip, port) может заблокировать поток на некоторое время. Внутри асинхронных функций лучше бы использовать метод SendAsync.
UDP и C# async/await