C# &引用;“无限”;异步并行foreach循环
我有一个包含5万到10万个单词的C# &引用;“无限”;异步并行foreach循环,c#,asynchronous,parallel-processing,async-await,C#,Asynchronous,Parallel Processing,Async Await,我有一个包含5万到10万个单词的列表 我想以并行和异步的方式对其进行迭代 例如,我可以使用 while (true) { Parallel.ForEach(words, new ParallelOptions { MaxDegreeOfParallelism = 100 }, ...) } 但问题是: Parallel.ForEach不是异步的 当我们到达列表的末尾时,我们必须等待每个线程在while(true)语句继续之前结束 这意味着不总是有100个线程在运行,这就是我想要的 我怎样
列表
我想以并行和异步的方式对其进行迭代
例如,我可以使用
while (true)
{
Parallel.ForEach(words, new ParallelOptions { MaxDegreeOfParallelism = 100 }, ...)
}
但问题是:
Parallel.ForEach
不是异步的while(true)
语句继续之前结束请让我知道这是否令人困惑,或者我是否不善于解释问题。下面是一个完全人为的
异步
友好示例,说明如何实现您的要求
private static CancellationTokenSource _cs;
private static CancellationToken _token;
private static ActionBlock<string> _block;
private static async Task MethodAsync(string something)
{
// Your async workload
}
public static async Task EndlessRunner(string[] someArray)
{
try
{
var index = 0;
while (!_token.IsCancellationRequested)
{
await _block.SendAsync(someArray[index],_token);
if (++index >= someArray.Length) index = 0;
}
}
catch (OperationCanceledException)
{
Console.WriteLine("Cancelled");
}
}
private static CancellationTokenSource\u cs;
私有静态取消令牌_令牌;
私有静态动作块_块;
私有静态异步任务方法异步(字符串)
{
//您的异步工作负载
}
公共静态异步任务EndlessRunner(字符串[]someArray)
{
尝试
{
var指数=0;
while(!\u token.iscancellationrequest)
{
wait _block.SendAsync(someArray[index],_令牌);
如果(++index>=someArray.Length)index=0;
}
}
捕获(操作取消异常)
{
控制台。写入线(“取消”);
}
}
示例
private static async Task Main()
{
_cs = new CancellationTokenSource();
_token = _cs.Token;
_block = new ActionBlock<string>(
MethodAsync,
new ExecutionDataflowBlockOptions()
{
EnsureOrdered = false,
MaxDegreeOfParallelism = 100,
BoundedCapacity = 100,
CancellationToken = _cs.Token,
SingleProducerConstrained = true
});
var someList = Enumerable
.Range(0,5000)
.Select(I => $"something {I}")
.ToArray();
Task.Run(() => EndlessRunner(someList));
Console.ReadKey();
_cs.Cancel();
_block.Complete();
await _block.Completion;
}
private静态异步任务Main()
{
_cs=新的CancellationTokenSource();
_令牌=_cs.token;
_块=新动作块(
MethodAsync,
新的ExecutionDataflowBlockOptions()
{
重新排序=错误,
MaxDegreeOfParallelism=100,
边界容量=100,
CancellationToken=\u cs.Token,
SingleProducerConstrained=true
});
var someList=可枚举
.范围(05000)
.Select(I=>$“something{I}”)
.ToArray();
Task.Run(()=>EndlessRunner(someList));
Console.ReadKey();
_cs.Cancel();
_block.Complete();
等待区块完工;
}
这是一个完全人为设计的异步
友好示例,说明如何实现您的要求
private static CancellationTokenSource _cs;
private static CancellationToken _token;
private static ActionBlock<string> _block;
private static async Task MethodAsync(string something)
{
// Your async workload
}
public static async Task EndlessRunner(string[] someArray)
{
try
{
var index = 0;
while (!_token.IsCancellationRequested)
{
await _block.SendAsync(someArray[index],_token);
if (++index >= someArray.Length) index = 0;
}
}
catch (OperationCanceledException)
{
Console.WriteLine("Cancelled");
}
}
private static CancellationTokenSource\u cs;
私有静态取消令牌_令牌;
私有静态动作块_块;
私有静态异步任务方法异步(字符串)
{
//您的异步工作负载
}
公共静态异步任务EndlessRunner(字符串[]someArray)
{
尝试
{
var指数=0;
while(!\u token.iscancellationrequest)
{
wait _block.SendAsync(someArray[index],_令牌);
如果(++index>=someArray.Length)index=0;
}
}
捕获(操作取消异常)
{
控制台。写入线(“取消”);
}
}
示例
private static async Task Main()
{
_cs = new CancellationTokenSource();
_token = _cs.Token;
_block = new ActionBlock<string>(
MethodAsync,
new ExecutionDataflowBlockOptions()
{
EnsureOrdered = false,
MaxDegreeOfParallelism = 100,
BoundedCapacity = 100,
CancellationToken = _cs.Token,
SingleProducerConstrained = true
});
var someList = Enumerable
.Range(0,5000)
.Select(I => $"something {I}")
.ToArray();
Task.Run(() => EndlessRunner(someList));
Console.ReadKey();
_cs.Cancel();
_block.Complete();
await _block.Completion;
}
private静态异步任务Main()
{
_cs=新的CancellationTokenSource();
_令牌=_cs.token;
_块=新动作块(
MethodAsync,
新的ExecutionDataflowBlockOptions()
{
重新排序=错误,
MaxDegreeOfParallelism=100,
边界容量=100,
CancellationToken=\u cs.Token,
SingleProducerConstrained=true
});
var someList=可枚举
.范围(05000)
.Select(I=>$“something{I}”)
.ToArray();
Task.Run(()=>EndlessRunner(someList));
Console.ReadKey();
_cs.Cancel();
_block.Complete();
等待区块完工;
}
您几乎肯定不希望100个线程始终运行……1)为什么希望它是异步的?考虑到它在一个无限循环中,这将是危险的。另外,您不应该将async/await
与Parallel.xxx
2)一起使用,因此3)可能是,可能不是Parallel.xxx
的动态线程池大小调整非常智能。您可能需要考虑TPL数据流,因为它支持流水线;限制和限制,并与async配合使用。TPLDF同时满足CPU绑定和I/O绑定的作业。如果您确实希望同时运行100个线程(同样,您确实不希望,您一定很困惑),那么您必须手动使用线程对象。Net中的异步实现将自行处理线程以获得最佳数量,并且除非您有128个核心服务器,否则它不会分配100个线程一次运行。任何时候使用wait时,线程池线程都会选择延续,并且很可能不会有100个线程池线程“我正在使用HttpClient”-那么您肯定不想增加“100个线程”。旋转一个只等待I/O的线程是对线程的浪费。让一个线程只处理一个网络链接更糟糕Parallel.xxx
使用async/await
非常危险,您希望后者支持IOCP。最好使用TPL数据流和async/await
。对于这类事情来说,这真是太棒了Parallel.ForEach
最适合用于CPU限制的操作,这似乎是一个X/Y问题-为什么您认为需要同时运行100个线程?您几乎肯定不希望总是运行100个线程…1)为什么希望它是异步的?考虑到它在一个无限循环中,这将是危险的。另外,您不应该将async/await
与Parallel.xxx
2)一起使用,因此3)可能是,可能不是Parallel.xxx
的动态线程池大小调整非常智能。您可能需要考虑TPL数据流,因为它支持流水线;限制和限制,并与async配合使用。TPLDF同时满足CPU绑定和