Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/webpack/2.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# 一次只运行X个任务_C#_Multithreading_Task - Fatal编程技术网

C# 一次只运行X个任务

C# 一次只运行X个任务,c#,multithreading,task,C#,Multithreading,Task,比如说,我有100个任务,这些任务只需要10秒钟就可以完成。 现在我只想在10个任务中的1个完成另一个任务时运行10个,直到所有任务都完成 现在我总是使用ThreadPool.QueueUserWorkItem()来完成这样的任务,但我已经读到这样做是不好的做法,我应该使用任务来代替 我的问题是,我没有找到一个适合我的场景的好例子,所以你能让我开始了解如何通过任务实现这个目标吗?你有几个选择。您可以使用Parallel.Invoke启动程序: public void DoWork(IEnumer

比如说,我有100个任务,这些任务只需要10秒钟就可以完成。 现在我只想在10个任务中的1个完成另一个任务时运行10个,直到所有任务都完成

现在我总是使用
ThreadPool.QueueUserWorkItem()
来完成这样的任务,但我已经读到这样做是不好的做法,我应该使用任务来代替


我的问题是,我没有找到一个适合我的场景的好例子,所以你能让我开始了解如何通过任务实现这个目标吗?

你有几个选择。您可以使用
Parallel.Invoke
启动程序:

public void DoWork(IEnumerable<Action> actions)
{
    Parallel.Invoke(new ParallelOptions() { MaxDegreeOfParallelism = 10 }
        , actions.ToArray());
}
如果您没有MoreLinq,那么对于
批处理
函数,下面是我的简单实现:

public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> source, int batchSize)
{
    List<T> buffer = new List<T>(batchSize);

    foreach (T item in source)
    {
        buffer.Add(item);

        if (buffer.Count >= batchSize)
        {
            yield return buffer;
            buffer = new List<T>();
        }
    }
    if (buffer.Count >= 0)
    {
        yield return buffer;
    }
}
公共静态IEnumerable批处理(此IEnumerable源代码,int batchSize)
{
列表缓冲区=新列表(batchSize);
foreach(源中的T项)
{
缓冲区。添加(项);
如果(buffer.Count>=batchSize)
{
收益返回缓冲区;
buffer=新列表();
}
}
如果(buffer.Count>=0)
{
收益返回缓冲区;
}
}

您有几种选择。您可以使用
Parallel.Invoke
启动程序:

public void DoWork(IEnumerable<Action> actions)
{
    Parallel.Invoke(new ParallelOptions() { MaxDegreeOfParallelism = 10 }
        , actions.ToArray());
}
如果您没有MoreLinq,那么对于
批处理
函数,下面是我的简单实现:

public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> source, int batchSize)
{
    List<T> buffer = new List<T>(batchSize);

    foreach (T item in source)
    {
        buffer.Add(item);

        if (buffer.Count >= batchSize)
        {
            yield return buffer;
            buffer = new List<T>();
        }
    }
    if (buffer.Count >= 0)
    {
        yield return buffer;
    }
}
公共静态IEnumerable批处理(此IEnumerable源代码,int batchSize)
{
列表缓冲区=新列表(batchSize);
foreach(源中的T项)
{
缓冲区。添加(项);
如果(buffer.Count>=batchSize)
{
收益返回缓冲区;
buffer=新列表();
}
}
如果(buffer.Count>=0)
{
收益返回缓冲区;
}
}
信号量lim maxThread=新信号量lim(10);
对于(int i=0;i<115;i++)
{
maxThread.Wait();
Task.Factory.StartNew(()=>
{
//你的作品
}
,TaskCreationOptions.LongRunning)
.ContinueWith((任务)=>maxThread.Release());
}
信号量lim maxThread=新信号量lim(10);
对于(int i=0;i<115;i++)
{
maxThread.Wait();
Task.Factory.StartNew(()=>
{
//你的作品
}
,TaskCreationOptions.LongRunning)
.ContinueWith((任务)=>maxThread.Release());
}
非常适合做这样的事情。您可以创建100%异步版本的
Parallel。调用
非常容易:

async Task ProcessTenAtOnce<T>(IEnumerable<T> items, Func<T, Task> func)
{
    ExecutionDataflowBlockOptions edfbo = new ExecutionDataflowBlockOptions
    {
         MaxDegreeOfParallelism = 10
    };

    ActionBlock<T> ab = new ActionBlock<T>(func, edfbo);

    foreach (T item in items)
    {
         await ab.SendAsync(item);
    }

    ab.Complete();
    await ab.Completion;
}
async Task processtenance(IEnumerable items,Func-Func)
{
ExecutionDataflowBlockOptions edfbo=新的ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism=10
};
ActionBlock ab=新的ActionBlock(func,edfbo);
foreach(项目中的T项目)
{
等待ab.SendAsync(项目);
}
ab.完成();
等待ab.完成;
}
非常适合做这样的事情。您可以创建100%异步版本的
Parallel。调用
非常容易:

async Task ProcessTenAtOnce<T>(IEnumerable<T> items, Func<T, Task> func)
{
    ExecutionDataflowBlockOptions edfbo = new ExecutionDataflowBlockOptions
    {
         MaxDegreeOfParallelism = 10
    };

    ActionBlock<T> ab = new ActionBlock<T>(func, edfbo);

    foreach (T item in items)
    {
         await ab.SendAsync(item);
    }

    ab.Complete();
    await ab.Completion;
}
async Task processtenance(IEnumerable items,Func-Func)
{
ExecutionDataflowBlockOptions edfbo=新的ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism=10
};
ActionBlock ab=新的ActionBlock(func,edfbo);
foreach(项目中的T项目)
{
等待ab.SendAsync(项目);
}
ab.完成();
等待ab.完成;
}

我想使用我能想到的最简单的解决方案,就像我想使用第三方物流一样:

string[] urls={};
Parallel.ForEach(urls, new ParallelOptions() { MaxDegreeOfParallelism = 2}, url =>
{
   //Download the content or do whatever you want with each URL
});

我希望使用我能想到的最简单的解决方案,正如我认为使用第三方物流:

string[] urls={};
Parallel.ForEach(urls, new ParallelOptions() { MaxDegreeOfParallelism = 2}, url =>
{
   //Download the content or do whatever you want with each URL
});

您可以创建如下方法:

public static async Task RunLimitedNumberAtATime<T>(int numberOfTasksConcurrent, 
    IEnumerable<T> inputList, Func<T, Task> asyncFunc)
{
    Queue<T> inputQueue = new Queue<T>(inputList);
    List<Task> runningTasks = new List<Task>(numberOfTasksConcurrent);
    for (int i = 0; i < numberOfTasksConcurrent && inputQueue.Count > 0; i++)
        runningTasks.Add(asyncFunc(inputQueue.Dequeue()));

    while (inputQueue.Count > 0)
    {
        Task task = await Task.WhenAny(runningTasks);
        runningTasks.Remove(task);
        runningTasks.Add(asyncFunc(inputQueue.Dequeue()));
    }

    await Task.WhenAll(runningTasks);
}
Task task = RunLimitedNumberAtATime(10,
    Enumerable.Range(1, 100),
    async x =>
    {
        Console.WriteLine($"Starting task {x}");
        await Task.Delay(100);
        Console.WriteLine($"Finishing task {x}");
    });
或者,如果您想运行长时间运行的非异步方法,可以这样做:

Task task = RunLimitedNumberAtATime(10,
    Enumerable.Range(1, 100),
    x => Task.Factory.StartNew(() => {
        Console.WriteLine($"Starting task {x}");
        System.Threading.Thread.Sleep(100);
        Console.WriteLine($"Finishing task {x}");
    }, TaskCreationOptions.LongRunning));

框架中可能有类似的方法,但我还没有找到。

您可以创建如下方法:

public static async Task RunLimitedNumberAtATime<T>(int numberOfTasksConcurrent, 
    IEnumerable<T> inputList, Func<T, Task> asyncFunc)
{
    Queue<T> inputQueue = new Queue<T>(inputList);
    List<Task> runningTasks = new List<Task>(numberOfTasksConcurrent);
    for (int i = 0; i < numberOfTasksConcurrent && inputQueue.Count > 0; i++)
        runningTasks.Add(asyncFunc(inputQueue.Dequeue()));

    while (inputQueue.Count > 0)
    {
        Task task = await Task.WhenAny(runningTasks);
        runningTasks.Remove(task);
        runningTasks.Add(asyncFunc(inputQueue.Dequeue()));
    }

    await Task.WhenAll(runningTasks);
}
Task task = RunLimitedNumberAtATime(10,
    Enumerable.Range(1, 100),
    async x =>
    {
        Console.WriteLine($"Starting task {x}");
        await Task.Delay(100);
        Console.WriteLine($"Finishing task {x}");
    });
或者,如果您想运行长时间运行的非异步方法,可以这样做:

Task task = RunLimitedNumberAtATime(10,
    Enumerable.Range(1, 100),
    x => Task.Factory.StartNew(() => {
        Console.WriteLine($"Starting task {x}");
        System.Threading.Thread.Sleep(100);
        Console.WriteLine($"Finishing task {x}");
    }, TaskCreationOptions.LongRunning));


也许框架中的某个地方也有类似的方法,但是我还没有找到它。

你在哪里读到过使用
线程池是一种不好的做法?我建议阅读一些文章或以前的Stackoverflow帖子有很多其他人尝试过的代码示例,在哪里可以找到答案?像我使用C#Stackoverflow ThreadPool.QueueUserWorkItem()一样进行谷歌搜索您想要一个阻塞直到所有任务都完成的方法,还是想要一个在所有任务都完成时返回
任务
的方法?它应该阻塞,就像ThreadPool一样,但对于任务。Stackoverflow上的一些人在一个代码示例中告诉我,Threadpool是一个不好的实践。你在哪里读到过使用
Threadpool
是一个不好的实践?我建议阅读一些文章或以前的Stackoverflow帖子,有很多其他人尝试过的代码示例,在哪里提供了答案请点击谷歌像我有C#Stackoverflow ThreadPool一样搜索。QueueUserWorkItem()您想要一个阻止所有任务完成的方法,还是想要一个在所有任务完成时返回
任务的方法?它应该阻止,就像ThreadPool一样,但要阻止任务。Stackoverflow上的一些人在一个代码示例中告诉我,Threadpool是一种不好的做法
现在我只想一次运行10个
,MaxDegreeOfParallelism只是一个上限。@L.B从技术上讲,如果工作单元的数量不能被10整除,那么就不可能正好是10个。即使是100个工作单元,它可能会运行更少的任务。它取决于许多参数,如#ofCPUs@L.B我知道这一点。我是说,即使你试图接近10,你也不可能总是完美的,你只能…更接近。@L.B我添加的附加版本满足你吗?
现在我只想一次运行10,
,MaxDegreeOfParallelism只是一个上限。@L.B哦,从技术上讲,如果工作单元的数量不能被10整除,那么精确的10是不可能的。不,即使有100个工作,它也可能运行更少的任务。它取决于许多参数,如#of