C# Linq调用任务。运行时访问错误的成员,延迟执行问题?
对于使用错误值的linq查询,我遇到了一个奇怪的问题。我的代码如下所示C# Linq调用任务。运行时访问错误的成员,延迟执行问题?,c#,linq,asynchronous,lambda,task,C#,Linq,Asynchronous,Lambda,Task,对于使用错误值的linq查询,我遇到了一个奇怪的问题。我的代码如下所示 await Task.WhenAll((from item in itemsToProcess let taskCount = count++ select Task.Run(() => { process(item).Result; })) .AsParallel().ToArray()); 基本上,我有一个50k项的列表,这些项被调用到一个进行web调用的方法中。它们完全不相关,可以以任何
await Task.WhenAll((from item in itemsToProcess
let taskCount = count++
select Task.Run(() => { process(item).Result; }))
.AsParallel().ToArray());
基本上,我有一个50k项的列表,这些项被调用到一个进行web调用的方法中。它们完全不相关,可以以任何顺序运行,并且不访问任何共享的内容。但是,有时,它会非常随机地将错误的项传递给process方法,就像在foreach循环中,如果不将其复制到局部变量,会遇到的情况一样
如果我把代码改成这个
await Task.WhenAll((from item in itemsToProcess
let taskCount = count++
let itemCopy = item
select Task.Run(() => { process(itemCopy).Result; }))
.AsParallel().ToArray());
那么我似乎没有这个问题。所以我的问题是,我是否遗漏了什么,或者这是预期的行为?我以为linq的from子句应该复制到本地副本,但事实不是这样吗?我很难找到任何能直接解决这个问题的方法。但是我看到了很多在linq表达式中调用异步方法而不执行额外let的示例
我也尝试过使lambda异步并等待该方法,但随后遇到了无线程的情况。也许有更好的方法?我很高兴知道这件事。简而言之,我所做的就是迭代一个列表并并行调用一个方法,因为它是I/O绑定的,而不是cpu绑定的。另一种可能是已经有很多关于这个的帖子了,我只是在寻找错误的术语。如果是这样的话,我也很高兴知道这一点。并行和异步代码很少应该一起使用。理想情况下,并行仅适用于CPU限制的代码 为什么你不能这样做:
await Task.WhenAll(itemsToProcess.Select(item => process(item)));
根据评论进行编辑:
通过使用信号量lim
,可以(在某种程度上)轻松完成异步节流:
static SemaphoreSlim throttle = new SemaphoreSlim(50);
static async Task ProcessAsync(Item item)
{
await throttle.WaitAsync();
try
{
... // Original process(item) code
}
finally
{
throttle.Release();
}
}
这将限制项目处理到50。这只是我从空气中提取的一个数字;你应该尝试一下,找到一个合适的值
请注意,一旦工作变为异步,并行处理节流就停止工作。异步工作不会“占用”线程,因此它不计入并行处理限制(或线程池注入速率限制)。这是一个很好的问题,我想知道如何摆脱并行调用。这个项目一开始是完全并行的,我决定异步重做,但我对异步非常陌生,所以我遇到了一些问题。当我这样做的时候,它实际上是在同一时间并行地运行每个调用,这会导致我的web调用超时,因为一次只能执行多个调用。使用任务池,它将任务限制为一次运行一定数量的任务,并将它们集中起来。如果有一种方法可以使用纯异步调用并将它们合并在一起,我认为这将是理想的。你的评论让这个出现在相关链接上,看起来像我可能需要的,谢谢!这似乎做得很好!你帮了大忙。我现在有很多测试要做,但这似乎工作得很好,在没有任务和跳过迭代的情况下,开销小得多。