我试图理解David对Task.Factory.StartNew
+ TaskCreationOptions.LongRunning
这里说了些什么。
注意:不要在异步代码中使用TaskCreationOptions.LongRunning,因为这将创建一个新线程,在等待之后将被销毁。
我知道在本例中没有必要使用Task.Run
或Task.Factory.StartNew
,因为SendLoopAsync和ReceiveLoopAsync是完全异步的。我还知道,如果这些方法中的任何一个都存在一个耗时的同步部分,那么Task.Run/Task.Factor.StartNew应该在该方法中。
大卫·福勒在他的声明中是什么意思?在异步任务中不应该有TaskCreationOptions.LongRunning
?或者他的意思是SendLoopAsync/ReceiveLoopAsync不应该是异步的?我还知道,TaskCreationOptions.LongRunning意味着任务将立即启动,这与调度程序安排的正常任务不同,可能需要一段时间才能结束。当同时启动多个连接时,您可以注意到这种行为,这导致发送和接收循环以显著延迟开始。
public async Task StartAsync(CancellationToken cancellationToken)
{
_ = Task.Factory.StartNew(_ => SendLoopAsync(cancellationToken), TaskCreationOptions.LongRunning, cancellationToken);
_ = Task.Factory.StartNew(_ => ReceiveLoopAsync(cancellationToken), TaskCreationOptions.LongRunning, cancellationToken);
}
private async Task SendLoopAsync()
{
await foreach (var message in _outputChannel.Reader.ReadAllAsync(_cancellationSource?.Token))
{
if (_clientWebSocket.State == WebSocketState.Open)
{
await _clientWebSocket.SendAsync(message.Data.AsMemory(), message.MessageType, true, CancellationToken.None).ConfigureAwait(false);
}
}
}
发布于 2022-04-19 07:37:30
David 手段表示SendLoopAsync
/ReceiveLoopAsync
不应该是异步的。如果任务要使用起始线程的持续时间(以纳秒为单位),以LongRunning
的形式启动任务是没有意义的。ThreadPool
是为了准确地处理这些情况而发明的。如果ThreadPool
由于饱和而没有足够的响应能力,那么尝试找出饱和的原因并修复它,而不是绕过ThreadPool
,每次有一些微秒的工作要做,创建新的线程就更符合逻辑了。
下面是LongRunning
与异步结合时发生的情况的演示:
var stopwatch = Stopwatch.StartNew();
Thread workerThread = null;
List<(string, long, System.Threading.ThreadState)> entries = new();
Task<Task> taskTask = Task.Factory.StartNew(async () =>
{
workerThread = Thread.CurrentThread;
entries.Add(("A", stopwatch.ElapsedMilliseconds, workerThread.ThreadState));
await Task.Delay(500);
entries.Add(("D", stopwatch.ElapsedMilliseconds, workerThread.ThreadState));
}, default, TaskCreationOptions.LongRunning, TaskScheduler.Default);
taskTask.Wait();
entries.Add(("B", stopwatch.ElapsedMilliseconds, workerThread.ThreadState));
workerThread.Join();
entries.Add(("C", stopwatch.ElapsedMilliseconds, workerThread.ThreadState));
await taskTask.Unwrap();
entries.Add(("E", stopwatch.ElapsedMilliseconds, workerThread.ThreadState));
foreach (var (title, elapsed, state) in entries)
Console.WriteLine($"{title } after {elapsed,3} msec worker thread is {state}");
输出:
A after 2 msec worker thread is Background
B after 6 msec worker thread is Background, Stopped
C after 6 msec worker thread is Stopped
D after 507 msec worker thread is Stopped
E after 507 msec worker thread is Stopped
工作线程的生存期最多为6毫秒。它真正需要做的就是实例化异步状态机,并使用System.Threading.Timer
组件调度回调。在我看来,6毫秒对于如此微小的工作负载来说就像一个eon。很可能这6毫秒用于线程间通信以及线程的创建和销毁。
https://stackoverflow.com/questions/71920524
复制相似问题