首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Task.Factory.StartNew + TaskCreationOptions.LongRunning解释

Task.Factory.StartNew + TaskCreationOptions.LongRunning解释
EN

Stack Overflow用户
提问于 2022-04-19 06:27:31
回答 1查看 522关注 0票数 1

我试图理解David对Task.Factory.StartNew + TaskCreationOptions.LongRunning 这里说了些什么。

注意:不要在异步代码中使用TaskCreationOptions.LongRunning,因为这将创建一个新线程,在等待之后将被销毁。

我知道在本例中没有必要使用Task.RunTask.Factory.StartNew,因为SendLoopAsync和ReceiveLoopAsync是完全异步的。我还知道,如果这些方法中的任何一个都存在一个耗时的同步部分,那么Task.Run/Task.Factor.StartNew应该在该方法中。

大卫·福勒在他的声明中是什么意思?在异步任务中不应该有TaskCreationOptions.LongRunning?或者他的意思是SendLoopAsync/ReceiveLoopAsync不应该是异步的?我还知道,TaskCreationOptions.LongRunning意味着任务将立即启动,这与调度程序安排的正常任务不同,可能需要一段时间才能结束。当同时启动多个连接时,您可以注意到这种行为,这导致发送和接收循环以显著延迟开始。

代码语言:javascript
运行
复制
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);
        }
    }
}
EN

Stack Overflow用户

回答已采纳

发布于 2022-04-19 07:37:30

David 手段表示SendLoopAsync/ReceiveLoopAsync不应该是异步的。如果任务要使用起始线程的持续时间(以纳秒为单位),以LongRunning的形式启动任务是没有意义的。ThreadPool是为了准确地处理这些情况而发明的。如果ThreadPool由于饱和而没有足够的响应能力,那么尝试找出饱和的原因并修复它,而不是绕过ThreadPool,每次有一些微秒的工作要做,创建新的线程就更符合逻辑了。

下面是LongRunning与异步结合时发生的情况的演示:

代码语言:javascript
运行
复制
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}");

输出:

代码语言:javascript
运行
复制
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

在Fiddle上试试

工作线程的生存期最多为6毫秒。它真正需要做的就是实例化异步状态机,并使用System.Threading.Timer组件调度回调。在我看来,6毫秒对于如此微小的工作负载来说就像一个eon。很可能这6毫秒用于线程间通信以及线程的创建和销毁。

票数 1
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71920524

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档