I'm trying to understand what David Fowler said about Task.Factory.StartNew
+ TaskCreationOptions.LongRunning
I'm trying to understand what David Fowler said about Task.Factory.StartNew
+ TaskCreationOptions.LongRunning
here.
???? NOTE: Don't use TaskCreationOptions.LongRunning with async code as this will create a new thread which will be destroyed after first await.
I know that there is no point of having Task.Run
or Task.Factory.StartNew
in this case because SendLoopAsync and ReceiveLoopAsync are completely async. I also know that if there is a time-consuming synchronous part inside either one of these methods, the Task.Run/Task.Factory.StartNew should be inside that method.
What does David Fowler mean in his statement? That there shouldn't be TaskCreationOptions.LongRunning
from within an async task? Or he meant that SendLoopAsync/ReceiveLoopAsync should not be async? I also know that TaskCreationOptions.LongRunning means that the task will start immediately, which isn't the case with just a normal task which gets scheduled by the scheduler, and might take some time to wind up. You can notice this behavior when starting multiple connections concurrently, which caused the Send and Receive loop to start with a significant delay.
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);
}
}
}
发布评论
评论(1)
大卫·福勒=“ nofollow noreferrer”>表示
sendloopasync
/aceiveloopAsync
不应是异步。 ,如果此任务将在纳秒内测量的持续时间内使用起始线程。 发明是为了准确处理这些类型的情况。如果threadpool
由于已经饱和而响应不足,那么尝试找到饱和的原因并修复它是更合理的,而不是绕过thread> threadpool
,并且每次您要做的工作值得一秒钟时,都会创建新线程。这是
longRunning
与异步:output:
。
工人线的寿命最多是6毫秒。它真正要做的就是实例化异步状态机,并使用
system.threading.timer
组件安排回调。 6毫秒对我来说就像是一个微小工作量的eon。这6毫秒很可能用于线程间的交流以及线程的创建和破坏。David Fowler means that the
SendLoopAsync
/ReceiveLoopAsync
should not be async. There is no point at starting a task asLongRunning
, if this task is going to use the starting thread for a duration measured in nanoseconds. TheThreadPool
was invented in order to handle exactly these types of situations. In case theThreadPool
is not responsive enough because it has become saturated, then it's more logical to try to find the cause of the saturation and fix it, instead of bypassing theThreadPool
, and creating new threads every time you have some microseconds-worth of work to do.Here is a demonstration of what happens when
LongRunning
is combined with async:Output:
Try it on Fiddle.
The lifetime of the worker thread was at most 6 milliseconds. All it really had to do was to instantiate an async state machine, and schedule a callback using a
System.Threading.Timer
component. 6 milliseconds look to me like an eon for such a minuscule workload. Most probably these 6 milliseconds were spent for inter-thread communication, and for the thread's creation and destruction.