我想了解我写的代码,
for (int i = 0; i< 5; i++)
{
ExecuteCMD("/c robocopy C:\\Source D:\\Source /MIR", true);
}
public async void ExecuteCMD(string cmdLine, bool waitForExit)
{
await Task.Factory.StartNew(() =>
{
ExecuteProcess proc = new ExecuteProcess(cmdLine, waitForExit);
proc.Execute();
} );
}
异步方法ExecuteCMD将循环运行5次。我知道async不会创建新线程。那么,是否在同一个线程中创建了5个具有相同名称(&#39; proc&#39;)的对象?请解释
非常感谢提前!
答案 0 :(得分:2)
你的意思是你的ExecuteProcess proc
对象?这是lambda函数的局部变量。所以你的代码没有冲突。
The Lambda
() =>
{
ExecuteProcess proc = new ExecuteProcess(cmdLine, waitForExit);
proc.Execute();
}
被称为5次,但每次调用只为变量ExecuteProcess
创建proc
的一个实例。
答案 1 :(得分:2)
您正在使用Task.Factory.StartNew
,因此您很可能(请参阅Stephen Cleary的评论)最终会出现在默认TaskScheduler
上,这恰好会在线程池线程上执行。因此,您的ExecuteProcess
分配和Execute
调用将在线程池线程上发生5次(如上所述,请参见上面的点默认调度程序) - 并且很可能彼此并行,和< / em>与你的for
循环并行(这最后一部分可能很难解决,但这是async void
的整个问题 - 执行顺序是非确定性的;稍后会详细介绍)。
你是有点,因为async/await
不一定会创建新线程。 async/await
是关于链接任务及其延续的全部内容,以便它们以相互正确的顺序执行。实际Task
次运行的位置取决于Task
的创建方式。在这里,您显式请求将您的工作推送到线程池,因为这是由Task
执行的Task.Factory.StartNew
执行的地方。
其他人指出你可能错误地使用async void
- 可能是由于缺乏理解。 async void
仅适用于以一种即发即弃的方式安排工作,并且这项工作需要是自包含的,并且具有自己的异常处理和并发控制。因为您的async void
将无法观察,并行将运行到其余代码中。它就像是说:“我希望这段代码在将来的某个时刻运行。我不需要知道它何时完成或是否引发了任何例外 - 我只是等到它碰到第一个{{1然后继续执行我自己的工作 - await
的其余部分将独立进行,无需监督“。因此,如果您在 async void
循环之后放置一些代码,那么很可能会在 for
工作之前执行,这可能会或可能会不是你想要的。
以下是您的应用程序实际发生情况的逐步视图。
您在主线程上遇到了ExecuteProcess
循环的第一次迭代。运行时调用for
,就像它是任何其他同步方法调用一样。它进入方法并在主线程上执行代码前面的 ExecuteCMD
,仍然是第一个await
循环迭代的一部分。然后它通过for
在线程池上安排一些工作。这项工作将在未来的某个时刻执行,比方说,线程池线程#1。然后等待Task.Factory.StartNew
返回的Task
。此任务不可能同步完成,因此Task.Factory.StartNew
计划将来运行的await
的其余部分(在主线程上,{{1创建的任务之后)已完成)和收益率。此时你的async void
工作可能还没有开始,但主线程已经可以自由跳转到Task.Factory.StartNew
循环的第二次迭代。它正是如此,这导致另一个任务被安排在线程池线程#2上运行,在未来的某个时刻 - 然后是另一个计划在主线程上运行的延续。然后ExecuteProcess
循环跳转到下一个项目。
当你的for
循环结束时,你很可能有5 for
个等待在线程池线程上执行,然后是5个继续for
等待在主线程。它们将在未来的某个时刻完成。您的代码不会知道何时因为您告诉它您不关心(使用Task
)。