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);
}
}
}