【发布时间】:2019-07-31 09:38:37
【问题描述】:
我首先要说的是,我目前正在学习多线程,所以可能不是我说的所有内容都是正确的 - 请随时根据需要纠正我。我确实对 async 和 await 有一个合理的理解。
我的基本目标如下: 我有一段代码,目前大约需要 3 秒。我试图在方法开始时加载一些数据,这些数据将在最后使用。我的计划是一开始就在不同的线程上加载数据——让其余代码独立执行。然后,在我需要数据的时候,如果没有加载数据,代码将等待。到目前为止,这一切似乎都运行良好,正如我所描述的那样。
我的问题与当我在并行 for 循环中调用异步方法而不等待它时会发生什么有关。
我的代码遵循这个结构:
public void MainCaller()
{
List<int> listFromThread = null;
var secondThread = Task.Factory.StartNew(() =>
{
listFromThread = GetAllLists().Result;
});
//Do some other stuff
secondThread.Wait();
//Do not pass this point until this thread has completed
}
public Task<List<int>> GetAllLists()
{
var intList = new List<int>(){ /*Whatever... */};
var returnList = new List<int>();
Parallel.ForEach(intList, intEntry =>
{
var res = MyMethod().Result;
returnList.AddRange(res);
});
return Task.FromResult(returnList);
}
private async Task<List<int>> MyMethod()
{
var myList = await obtainList.ToListAsync();
}
注意 Parallel for Loop 调用 async 方法,但不等待它,因为它本身不是异步的。
这是一个在别处使用的方法,所以它是异步的是有效的。我知道一种选择是复制这个非异步的方法,但我想了解这里会发生什么。
我的问题是,我能否确定当我到达secondThread.Wait(); 时,执行的异步部分将完成。例如,将等待知道等待异步部分完成,或者异步会扰乱等待,还是会无缝地协同工作?
在我看来,可能由于未等待对 MyMethod 的调用,但在 MyMethod 中有等待,并行 for 循环可以在等待的调用完成之前继续执行吗?
那么我认为,因为它是通过引用分配它,所以一旦分配发生,该值将是正确的结果。
这让我认为只要等待知道等待异步完成,那么就没有问题 - 因此我的问题。
我猜这与我对 Tasks 缺乏了解有关?
我希望这很清楚?
【问题讨论】:
-
我的看法是,整个拱门都搞砸了。首先,消除
.Wait,然后消除.Results,然后消除Parallel.ForEach...我觉得这里不需要它们。现在,您应该真正了解异步和并行之间的区别了。 -
@AgentFire 你能解释一下为什么我应该删除所有这些东西吗?
-
一般来说,您不应该在
Tasks 上使用.Result和/或.Wait,因为这会导致阻塞调用,从而破坏异步/等待的整个目的。每当您使用.Wait或.Result时,请考虑如何以不同的方式进行操作。如果您仅通过Task.FromResult创建它并且不使用任何awaits,则还应避免返回一些Task,因为它只会给您带来更差的性能,并且与仅将其正常返回而不将其包装到任务中相比没有任何好处。 -
@Joelius 我不是想利用 await 的好处 - 我只是想了解我在问题中提出的要点
-
实际上,在您的 parallel.for 循环中,您正在同步调用 MyMethod,因为您正在调用 'MyMethod().Result。所以从这个循环开始的每个任务都会阻塞,直到 MyMethod 完成。
标签: c# multithreading asynchronous task