Task.Factory.StartNew中的随机任务永远不会完成 [英] Random tasks from Task.Factory.StartNew never finishes
问题描述
我正在通过Task.Factory方法使用Async等待.
I am using Async await with Task.Factory method.
public async Task<JobDto> ProcessJob(JobDto jobTask)
{
try
{
var T = Task.Factory.StartNew(() =>
{
JobWorker jobWorker = new JobWorker();
jobWorker.Execute(jobTask);
});
await T;
}
我正在这样的循环内调用此方法
This method I am calling inside a loop like this
for(int i=0; i < jobList.Count(); i++)
{
tasks[i] = ProcessJob(jobList[i]);
}
我注意到的是,新任务在Process Explorer中打开,它们也开始工作(基于日志文件).然而,在十个有时八或七个完成中.其他人再也不会回来了.
What I notice is that new tasks opens up inside Process explorer and they also start working (based on log file). however out of 10 sometimes 8 or sometimes 7 finishes. Rest of them just never come back.
- 为什么会这样?
- 他们超时了吗?在哪里可以为我的任务设置超时时间?
更新
基本上,我希望每个任务一被调用就开始运行,并等待对AWAIT T关键字的响应.我在这里假设一旦他们完成,每个人都会回到Await T并进行下一步行动.我很高兴看到10项任务中有7项的结果,但是其中3项没有回来.
Basically above, I would like each Task to start running as soon as they are called and wait for the response on AWAIT T keyword. I am assuming here that once they finish each of them will come back at Await T and do the next action. I am alraedy seeing this result for 7 out of 10 tasks but 3 of them are not coming back.
谢谢
推荐答案
首先,让我们制作代码的可复制版本.这不是实现您正在做的事情的最佳方法,而是向您展示代码中正在发生的事情!
First, let's make a reproducible version of your code. This is NOT the best way to achieve what you are doing, but to show you what is happening in your code!
我将使代码与您的代码几乎相同,除了我将使用简单的int
而不是您的JobDto
,并且在完成工作Execute()
之后,我将在一个文件中编写一个我们可以验证的文件之后.这是代码
I'll keep the code almost same as your code, except I'll use simple int
rather than your JobDto
and on completion of the job Execute()
I'll write in a file that we can verify later. Here's the code
public class SomeMainClass
{
public void StartProcessing()
{
var jobList = Enumerable.Range(1, 10).ToArray();
var tasks = new Task[10];
//[1] start 10 jobs, one-by-one
for (int i = 0; i < jobList.Count(); i++)
{
tasks[i] = ProcessJob(jobList[i]);
}
//[4] here we have 10 awaitable Task in tasks
//[5] do all other unrelated operations
Thread.Sleep(1500); //assume it works for 1.5 sec
// Task.WaitAll(tasks); //[6] wait for tasks to complete
// The PROCESS IS COMPLETE here
}
public async Task ProcessJob(int jobTask)
{
try
{
//[2] start job in a ThreadPool, Background thread
var T = Task.Factory.StartNew(() =>
{
JobWorker jobWorker = new JobWorker();
jobWorker.Execute(jobTask);
});
//[3] await here will keep context of calling thread
await T; //... and release the calling thread
}
catch (Exception) { /*handle*/ }
}
}
public class JobWorker
{
static object locker = new object();
const string _file = @"C:\YourDirectory\out.txt";
public void Execute(int jobTask) //on complete, writes in file
{
Thread.Sleep(500); //let's assume does something for 0.5 sec
lock(locker)
{
File.AppendAllText(_file,
Environment.NewLine + "Writing the value-" + jobTask);
}
}
}
仅运行StartProcessing()
之后,这就是我在文件中得到的内容
After running just the StartProcessing()
, this is what I get in the file
Writing the value-4
Writing the value-2
Writing the value-3
Writing the value-1
Writing the value-6
Writing the value-7
Writing the value-8
Writing the value-5
因此,已完成8/10个工作.显然,每次运行此命令时,编号和顺序可能都会更改.但是,关键是,所有工作都没有完成!
So, 8/10 jobs has completed. Obviously, every time you run this, the number and order might change. But, the point is, all the jobs did not complete!
现在,如果我取消对步骤[6] Task.WaitAll(tasks);
的注释,这就是我在文件中得到的内容
Now, if I un-comment the step [6] Task.WaitAll(tasks);
, this is what I get in my file
Writing the value-2
Writing the value-3
Writing the value-4
Writing the value-1
Writing the value-5
Writing the value-7
Writing the value-8
Writing the value-6
Writing the value-9
Writing the value-10
所以,我所有的工作都在这里完成!
So, all my jobs completed here!
代码注释中已经解释了为什么代码具有这种行为.要注意的主要事情是,您的任务在基于ThreadPool
的Background
线程中运行.因此,如果您不等待它们,它们将在MAIN进程结束且主线程退出时被杀死!
Why the code is behaving like this, is already explained in the code-comments. The main thing to note is, your tasks run in ThreadPool
based Background
threads. So, if you do not wait for them, they will be killed when the MAIN process ends and the main thread exits!!
如果您仍然不想在那里等待任务,则可以从第一个方法返回任务列表,并在过程结束时返回await
任务,类似这样
If you still don't want to await the tasks there, you can return the list of tasks from this first method and await
the tasks at the very end of the process, something like this
public Task[] StartProcessing()
{
...
for (int i = 0; i < jobList.Count(); i++)
{
tasks[i] = ProcessJob(jobList[i]);
}
...
return tasks;
}
//in the MAIN METHOD of your application/process
var tasks = new SomeMainClass().StartProcessing();
// do all other stuffs here, and just at the end of process
Task.WaitAll(tasks);
希望这可以消除所有的混乱.
Hope this clears all confusion.
这篇关于Task.Factory.StartNew中的随机任务永远不会完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!