对于最新的网络,我们默认有async Main
个方法.
此外,如果您没有该功能,您可以将Main
标记为异步.
这里的主要风险是您可能会错过异常,并且必须非常小心地处理创建的任务.如果您要在while (true)
循环中创建任务,很可能会在某个时刻(当有人错误地使用某个阻塞调用时)导致线程池匮乏.
下面的示例代码显示了应该考虑的内容,但我最确定的是,还会有更复杂的内容:
using System.Collections.Concurrent;
using System.Security.Cryptography.X509Certificates;
namespace ConsoleApp2;
public static class Program
{
/// <summary>
/// Property to track all running tasks, should be dealt with carefully.
/// </summary>
private static ConcurrentBag<Task> _runningTasks = new();
static Program()
{
// Subscribe to an event.
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
}
static async Task Main(string[] args)
{
var messageNo = 1;
while (true)
{
// Just schedule the work
// Here you should most probably limit number of
// tasks created.
var task = ReceiveMessage(messageNo)
.ContinueWith(t => TopLevelHandler(t.Result));
_runningTasks.Add(task);
messageNo++;
}
}
static async Task TopLevelHandler(object message)
{
await DoAsyncWork(message);
}
static async Task<object> ReceiveMessage(int messageNumber)
{
//fetch message from queue
await Task.Delay(5000);
return await Task.FromResult(messageNumber);
}
static async Task DoAsyncWork(object message)
{
//processing here
Console.WriteLine($"start processing message {message}");
await Task.Delay(5000);
// Only when you want to test catching exception
// throw new Exception("some malicious code");
Console.WriteLine($"end processing message {message}");
}
/// <summary>
/// Here you handle any unosberved exception thrown in a task.
/// Preferably you should handle somehow all running work in other tasks.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
static async void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
// Potentially this method could be enter by multiple tasks having exception.
Console.WriteLine($"Exception caught: {e.Exception.InnerException.Message}");
await Task.WhenAll(_runningTasks.Where(x => !x.IsCompleted));
}
}