我一直在使用System.Threading.Tasks.Task.Run()取得了巨大的成功。我最近发现我的一个进程过早退出,因为任务没有完成。显然,我没有第一个线索,System.Threading.Tasks.Task.Run()实际上是如何工作的,我的100,000多行C#代码(三个Windows服务,Web应用程序,数据库和内存进程间缓存)工作原理纯粹的运气。这是代码的简化版本。为什么在没有执行延迟的情况下退出流程?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TaskWaitDemo
{
class Program
{
static void Main(string[] args)
{
Task.Run(() =>
{
while (true)
{
try
{
Task.Delay(60 * 1000).Wait();
// In my actual code I perform real computation right here after the wait.
Console.WriteLine("why does this line never execute???");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
});
}
}
}
修改
尝试拥抱与线程无关的任务世界,我将任务用于两个主要目的:1)将工作排队到线程池,以及2)异步处理周期性任务。我上面的例子是一个过度简化的尝试来展示一个周期性任务的例子。在我的实际应用中,While (true) { ... }
实际上更像是while (!_shutdown) { ... }
。
各种评论和答案都建议只是等待任务,但在我的实际应用程序中,主线程在启动任务后可能有也可能没有事可做,而且不能简单地等待我的周期性任务而不会永远阻止。
在线程的旧时代,线程A将启动线程B,然后如果没有任何事情可以优雅地退出,让线程B快乐地做它的事情并且进程仍在运行。
似乎在勇敢的新任务世界中,线程A运行任务B(将一些工作(可能是周期性的)排队到线程池中,然后如果没有任何事情要做,则可以优雅地退出。然后,框架将任务B(以及显然通过任务排队到线程池的任何其他工作)扔到位桶中,并且该过程终止。似乎对我不利。
我想我的答案是使用好的旧线程进行周期性任务,并希望并祈祷在允许应用程序关闭之前,线程池队列中的所有即发即弃任务都已完成。
答案 0 :(得分:4)
你运行while(true)
,是的,这是正确的,但你在另一个线程上运行它。
相反,主线程会在Main
内全程运行并退出应用。
static void Main(string[] args)
{
//MAIN THREAD BOUNDS
//LAUNCH THE TASK AND GO AHEAD
var task = Task.Run(() => (EDIT)
{
//SECOND THREAD BOUNDS
while (true)
{
...
}
//--------------
});
task.Wait(); (EDIT) //WAIT FOR TASK COMPLETION !!!!
//NOTHING MORE TO DO, SO EXIT APP AND KILL Task.Run THREAD
}
修改强>
如果您需要等待完成,只需使用Task.Wait,就像编辑后的代码一样。在这个具体的例子中,它没有任何意义,这并不意味着它不会在你的中。
答案 1 :(得分:0)
您的任务的更好结构将是:
static void Main(string[] args)
{
var task = new Task(() =>
{
while (true)
{
Console.WriteLine("Computing..");
Thread.Sleep(1000);
}
});
task.Start();
task.Wait(); //Wait for the task to finish
}