Max*_*m T 5 c# multithreading threadpool task-parallel-library async-await
回答问题:Task.Yield - 实际用途? 我建议使用 Task.Yield 允许池线程被其他任务重用。在这样的模式中:
CancellationTokenSource cts;
void Start()
{
cts = new CancellationTokenSource();
// run async operation
var task = Task.Run(() => SomeWork(cts.Token), cts.Token);
// wait for completion
// after the completion handle the result/ cancellation/ errors
}
async Task<int> SomeWork(CancellationToken cancellationToken)
{
int result = 0;
bool loopAgain = true;
while (loopAgain)
{
// do something ... means a substantial work or a micro batch here - not processing a single byte
loopAgain = /* check for loop end && */ cancellationToken.IsCancellationRequested;
if (loopAgain) {
// reschedule the task to the threadpool and free this thread for other waiting tasks
await Task.Yield();
}
}
cancellationToken.ThrowIfCancellationRequested();
return result;
}
void Cancel()
{
// request cancelation
cts.Cancel();
}
Run Code Online (Sandbox Code Playgroud)
但是一位用户写道
我不认为在实现生产者/消费者模式的同时使用 Task.Yield 来克服 ThreadPool 饥饿是一个好主意。如果您想详细了解原因,我建议您提出一个单独的问题。
有谁知道,为什么不是一个好主意?
对你的问题的评论中留下了一些很好的观点。作为您引用的用户,我只想总结一下:使用正确的工具来完成工作。
使用ThreadPool
感觉不是执行多个连续的 CPU 密集型任务的正确工具,即使您尝试通过将它们转变为状态机来组织一些协作执行,从而为彼此提供 CPU 时间await Task.Yield()
。线程切换的开销相当大;通过await Task.Yield()
在紧密的循环中执行,您会增加大量的开销。此外,您永远不应该接管整个ThreadPool
.NET 框架(和底层操作系统进程)可能需要它来做其他事情。与此相关的是,TPL 甚至可以选择TaskCreationOptions.LongRunning
请求不在线程上运行任务(而是在幕后ThreadPool
创建一个普通线程)。new Thread()
也就是说,在一些专用的、池外线程上使用具有有限并行性的自定义,并且对单个长时间运行的任务具有线程关联性 可能是另一回事。至少,延续将被发布在同一个线程上,这应该有助于减少切换开销。这让我想起了不久前我试图解决的另一个问题。TaskScheduler
await
ThreadAffinityTaskScheduler
不过,根据特定场景,通常最好使用现有的成熟且经过测试的工具。仅举几例:Parallel Class、TPL Dataflow、System.Threading.Channels、Reactive Extensions。
还有一整套现有的工业级解决方案来处理发布-订阅模式(RabbitMQ、PubNub、Redis、Azure 服务总线、Firebase 云消息传递 (FCM)、Amazon 简单队列服务 (SQS) 等)。
归档时间: |
|
查看次数: |
1633 次 |
最近记录: |