如何正确使用 LongRunning Task

360影视 动漫周边 2025-06-03 08:52 2

摘要:在上一篇文章《如何正确实现一个后台(定时)任务》中有提到使用LongRunningTask 来优化后台任务始终保持在同一个线程上。protectedoverrideTaskExecuteAsync(CancellationToken stoppingToken

在上一篇文章《如何正确实现一个后台(定时)任务》中有提到使用LongRunningTask 来优化后台任务始终保持在同一个线程上。protectedoverrideTaskExecuteAsync(CancellationToken stoppingToken)
{
returnTask.Factory.StartNew(async =>
{
while(!stoppingToken.IsCancellationRequested)
{
// Simulate some work
Console.WriteLine("HostServiceTest_A is doing work.");

LongTermTask;

awaitTask.Delay(1000, stoppingToken);// Delay for 1 second
}

Console.WriteLine("HostServiceTest_A task done.");

}, TaskCreationOptions.LongRunning);
}

privatevoidLongTermTask
{

Console.WriteLine("LongTermTaskA is doing work.");
Thread.Sleep(30000);
}
但是被黑洞视界大佬指出这个用法是错误的:以上用法并不能保证任务始终在同一个Task(线程) 上执行。原因是当碰到第一个await之后运行时会从ThreadPool中调度一个新的线程来执行后面的代码,而当前线程被释放。这个时候就不符合我们使用LongRunning的期望了。在 .NET 中,Task.Factory.StartNew提供了TaskCreationOptions.LongRunning选项,很多开发者会用它来启动长时间运行的任务,并且想当然的认为它会永远执行在同一个线程上。但是事实上当遇到asyncawait的时候并想象的那么简单。

下面我们还是通过一个错误的示例开始讲解如何正确的使用它。

很多人会直接在里传入一个async方法:// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");

vartask = Task.Factory.StartNew(async =>
{
Console.WriteLine($"long running task starting. Thread id: {Thread.CurrentThread.ManagedThreadId}");
varloopcount =1;
while(true)
{
Console.WriteLine($"\r\nStart: loop count: {loopCount}, Thread id: {Thread.CurrentThread.ManagedThreadId}");
awaitLongRunningJob;
Console.WriteLine($"End: loop count: {loopCount}, Thread id: {Thread.CurrentThread.ManagedThreadId} \r\n ");
loopCount++;
}

}, TaskCreationOptions.LongRunning);

staticasyncTaskLongRunningJob
{
Console.WriteLine($"task doing. Thread id: {Thread.CurrentThread.ManagedThreadId}");
awaitTask.Delay(1000);
}

Console.ReadLine;

输出:

Hello, World!
long running task starting. Thread id: 12

Start: loop count: 1, Thread id: 12
task doing. Thread id: 12
End: loop count: 1, Thread id: 11

Start: loop count: 2, Thread id: 11
task doing. Thread id: 11
End: loop count: 2, Thread id: 11
可以看到,第一次循环后,线程 id 发生了变化。很明显LongRunning失效了。原因开篇已经讲了,不再赘述。将改为同步方法,避免异步切换线程:vartask = Task.Factory.StartNew( =>
{
Console.WriteLine($"long running task starting. Thread id: {Thread.CurrentThread.ManagedThreadId}");
varloopCount =1;
while(true)
{
Console.WriteLine($"\r\nStart: loop count: {loopCount}, Thread id: {Thread.CurrentThread.ManagedThreadId}");
LongRunningJob;
Console.WriteLine($"End: loop count: {loopCount}, Thread id: {Thread.CurrentThread.ManagedThreadId} \r\n ");
loopCount++;
}

}, TaskCreationOptions.LongRunning);

staticvoidLongRunningJob
{
Console.WriteLine($"task doing. Thread id: {Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(1000);
}

输出:

Hello, World!
long running task starting. Thread id: 12

Start: loop count: 1, Thread id: 12
task doing. Thread id: 12
End: loop count: 1, Thread id: 12

线程 id 始终不变,说明始终运行在专用线程上。

如果必须用异步方法,可以用让调用变为同步:vartask = Task.Factory.StartNew( =>
{
Console.WriteLine($"long running task starting. Thread id: {Thread.CurrentThread.ManagedThreadId}");
varloopCount =1;
while(true)
{
Console.WriteLine($"\r\nStart: loop count: {loopCount}, Thread id: {Thread.CurrentThread.ManagedThreadId}");
LongRunningJob.Wait;
Console.WriteLine($"End: loop count: {loopCount}, Thread id: {Thread.CurrentThread.ManagedThreadId} \r\n ");
loopCount++;
}

}, TaskCreationOptions.LongRunning);

staticasyncTaskLongRunningJob
{
Console.WriteLine($"task doing. Thread id: {Thread.CurrentThread.ManagedThreadId}");
awaitTask.Delay(1000);
}

输出:

希望本文能帮你正确理解和使用LongRunning任务!

来源:opendotnet

相关推荐