Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#任务线程池-仅跨10个线程运行100个任务_C#_Multithreading_Async Await - Fatal编程技术网

C#任务线程池-仅跨10个线程运行100个任务

C#任务线程池-仅跨10个线程运行100个任务,c#,multithreading,async-await,C#,Multithreading,Async Await,我只是想知道是否有人能为我指出异步/等待框架和线程池的正确方向 基本上,我要做的是在一个单独的线程/异步中执行x个操作,但最多执行y个线程 例如,假设我有100个数据库操作: wait_repository.WriteData(someData) 我想做的是有一些方法一次运行10个这样的操作(理想情况下,每个操作在一个单独的线程中,因此是10个线程),当每一个操作完成时,下一个操作将在线程上启动,然后该线程将变为可用。然后我们等待所有操作完成,所有线程完成 这是一种不需要太多努力或增加大量复杂性

我只是想知道是否有人能为我指出异步/等待框架和线程池的正确方向

基本上,我要做的是在一个单独的线程/异步中执行x个操作,但最多执行y个线程

例如,假设我有100个数据库操作:
wait_repository.WriteData(someData)

我想做的是有一些方法一次运行10个这样的操作(理想情况下,每个操作在一个单独的线程中,因此是10个线程),当每一个操作完成时,下一个操作将在线程上启动,然后该线程将变为可用。然后我们等待所有操作完成,所有线程完成


这是一种不需要太多努力或增加大量复杂性就可以轻松实现的方法吗?

我认为,如果您只关注线程,尤其是不需要线程执行的异步操作,那么您就没有抓住要点

.NET有一个很好的
线程池
,您可以使用它。你不知道里面有多少线程,你也不在乎。它只是工作(直到它不工作,您需要自己配置它,但这是非常先进的)

ThreadPool
上运行任务非常简单。为每个操作创建一个任务,并使用
信号量lim
限制它们,或者使用现成的TPL数据流块。例如:

var block = new ActionBlock<SomeData>(
    _ => _repository.WriteDataAsync(_), // What to do on each item
    new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 10 }); // How many items at the same time

foreach (var item in items)
{
    block.Post(item); // Post all items to the block
}

block.Complete(); // Signal completion
await block.Completion; // Asynchronously wait for completion.
var block=新动作块(
_=>\u repository.WriteDataAsync(\)//对每个项目执行什么操作
新的ExecutionDataflowBlockOptions{MaxDegreeOfParallelism=10});//同时有多少个项目
foreach(项目中的var项目)
{
block.Post(item);//将所有项发布到块中
}
block.Complete();//信号完成
等待区块完成;//异步等待完成。

但是,如果您确实计划创建“专用”线程,则可以使用
Task.Factory.StartNew
LongRunning
选项在
ThreadPool
之外创建专用线程。但是请记住,异步操作不需要在整个操作过程中维护相同的线程,因为异步操作不需要线程。因此,从一个专用线程开始可能毫无意义(更多信息请访问我的博客:)

@i3arnon的答案是正确的。使用TPL数据流

此答案的其余部分仅用于教育目的和/或特殊用例

我最近在一个项目中遇到了一个类似的问题,在这个项目中我无法引入任何外部依赖项,因此我不得不推出自己的负载平衡实现,结果证明它非常简单(直到您开始连接取消和有序结果-但这超出了这个问题的范围)

我忽略了“10个专用线程”的要求,因为正如其他人已经解释过的那样,它在处理异步操作时没有意义。相反,我将维护多达
N
并发
Task
实例来处理工作负载

static async Task InvokeAsync(IEnumerable taskFactories,int-maxDegreeOfParallelism)
{
队列=新队列(任务工厂);
如果(queue.Count==0){
返回;
}
列表任务飞行=新列表(maxDegreeOfParallelism);
做
{
while(tasksInFlight.Count
用法:

Func<Task>[] taskFactories = {
    () => _repository.WriteData(someData1),
    () => _repository.WriteData(someData2),
    () => _repository.WriteData(someData3),
    () => _repository.WriteData(someData4)
};

await InvokeAsync(taskFactories, maxDegreeOfParallelism: 2);
Func[]任务工厂={
()=>_repository.WriteData(someData1),
()=>_repository.WriteData(someData2),
()=>_repository.WriteData(someData3),
()=>_repository.WriteData(someData4)
};
等待调用同步(TaskFactorys,maxDegreeOfParallelism:2);
。。。或

IEnumerable<SomeData> someDataCollection = ... // Get data.

await ParallelTasks.InvokeAsync(
    someDataCollection.Select(someData => new Func<Task>(() => _repository.WriteData(someData))),
    maxDegreeOfParallelism: 10
);
IEnumerable someDataCollection=…//获取数据。
等待ParallelTasks.InvokeAsync(
someDataCollection.Select(someData=>newfunc(()=>_repository.WriteData(someData)),
最大平行度:10
);
此解决方案不会出现负载平衡差的问题,这在任务具有不同持续时间且输入已预分区(例如)的情况下,在其他平凡的实现中经常会看到


具有性能优化和参数验证的版本:。

为什么不使用wait并让框架为您处理线程呢?您是否做过任何性能测试,表明该框架不适合您的需要?@gabriel该框架不知道最佳IO并行。它怎么会知道呢?@Eser,我同意这是一个复制品,但给出的答案已经是高质量的了,所以这看起来很有希望等等,我很困惑。如果它们是IO操作,那么为什么会有线程?你不会在收到的每封信中雇佣一名员工负责在邮箱旁等待那封信。为什么要雇佣一堆线程坐在那里等待数据库?不,不是这样,但在本例中,数据库服务器将负责处理并行IO操作的数据库操作。这实际上取决于他没有指定的用例是什么。TPL数据流非常适合所述问题。不知道为什么会有人对此投反对票。TPL数据流不是“内置的”。我从你的博客上了解到,haha@i3arnon当10个任务中的任何一个任务完成时,如何向队列添加新任务。表示向队列中添加新任务。这里我的目标是,例如,如果我们已经通过SemaphoreSlim或MaxDegreeOfParallelism设置了一次运行10个任务的限制,但我不想创建100个任务,然后通过SemaphoreSlim或MaxDegreeOfParallelism设置限制
IEnumerable<SomeData> someDataCollection = ... // Get data.

await ParallelTasks.InvokeAsync(
    someDataCollection.Select(someData => new Func<Task>(() => _repository.WriteData(someData))),
    maxDegreeOfParallelism: 10
);