简体   繁体   English

如何限制 C# 中的任务数量,以便通过该数量的任务可以完成多项工作

[英]How to limit number of tasks in C# so that multiple works can be done through that number of tasks

I want to run 3 tasks parallel which will take input form one array of size n in a for loop.我想并行运行 3 个任务,这些任务将在 for 循环中从一个大小为 n 的数组中获取输入。 Once one task is completed it will take another input from the array and so on.一旦完成一项任务,它将从数组中获取另一个输入,依此类推。

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            int []Arr ={1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
            List<Task> tasks = new List<Task>();
            int maxConcurrency = 5;
            using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(maxConcurrency))
            {
                foreach (var x in Arr)
                {
                    concurrencySemaphore.Wait();
                    var t = Task.Run(async() =>
                    {
                        try
                        {
                            await concurrencySemaphore.WaitAsync();
                            print(x);
                        }
                        finally
                        {
                            concurrencySemaphore.Release();
                        }
                    });
                    int number = Process.GetCurrentProcess().Threads.Count;
                    Console.WriteLine("Thread {0} count {1}", t.Id, number);
                    tasks.Add(t);
                }
                Task.WaitAll(tasks.ToArray());
            }
            Console.ReadLine();
        }
        static void print(int x)
        {
            Console.WriteLine("Hello World! {0}", x);
        }
    }
}


    I expect the output should be hello world! 1-10 but the actual output is
    Hello World! 1
    Thread 2 count 12
    Hello World! 2
    Thread 4 count 12
    Hello World! 3
    Thread 6 count 12
    Hello World! 4
    Thread 8 count 12
    Thread 10 count 12

If you have any other suggestion then you are welcome.如果您有任何其他建议,那么欢迎您。

The problem with your code is that you have two wait statements, one blocking and one non-blocking.您的代码的问题是您有两个等待语句,一个是阻塞的,一个是非阻塞的。

concurrencySemaphore.Wait();
await concurrencySemaphore.WaitAsync();

You only need to wait once for an available semaphore.您只需要等待一次可用的信号量。 So If you comment out the concurrencySemaphore.Wait() line, your code will work as expected.因此,如果您注释掉 concurrencySemaphore.Wait() 行,您的代码将按预期工作。

Other things to note about your code:关于您的代码的其他注意事项:

Since you only designated one method for asynchronous processing (the WaitAsync method), this code will run exactly the same if you replace WaitAsync with Wait.由于您只为异步处理指定了一种方法(WaitAsync 方法),因此如果您将 WaitAsync 替换为 Wait,此代码将运行完全相同。 So, when using WaitAsync in this situation, the task will first execute the WaitAsync method, if it cannot enter a semaphore, it will put that statement on hold and execute another async statement.因此,在这种情况下使用 WaitAsync 时,任务将首先执行 WaitAsync 方法,如果它无法输入信号量,它将暂停该语句并执行另一个异步语句。 But since there are no more async methods defined, the code will just end up blocking until it can enter a semaphore.但是由于没有定义更多的异步方法,代码最终会阻塞,直到它可以输入信号量。

To prove your code is processing 5 Tasks at a time, you should add a call to the Sleep method in your PRINT function.为了证明您的代码一次处理 5 个任务,您应该在 PRINT function 中添加对 Sleep 方法的调用。 This will allow you to visually see the number of Tasks being process at any given time.这将允许您在任何给定时间直观地查看正在处理的任务数量。

Example:例子:

static void print(int x)
{
    Console.WriteLine("Hello World! {0}", x);
    Thread.Sleep(3000);  //Wait 3 seconds to allow other Task to process before exiting
}

To demonstrate here is a tweak version of your code with the Async/Await statements replace with Wait.此处演示的是代码的调整版本,其中 Async/Await 语句替换为 Wait。

class Program
{
    static void Main(string[] args)
    {
        int[] Arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        int maxConcurrency = 5;
        List<Task> tasks = new List<Task>();

        using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(0, maxConcurrency))
        {
            // Create a Task object for each element in the array
            foreach (var x in Arr)
            {

                tasks.Add(Task.Run(() =>
                {
                    // Block until the task can enter a semaphore
                    concurrencySemaphore.Wait();

                    // Do some work
                    print(x);

                    // Signal you are done with the semaphore
                    concurrencySemaphore.Release();
                }
                ));
        }

        // Wait a haft a second to allow all tasks to start and block.
        Thread.Sleep(500);

        // This will release "maxConcurrency" tasks to be process at a given time.
        concurrencySemaphore.Release(maxConcurrency);

        // Main thread waits for all tasks to complete.
        Task.WaitAll(tasks.ToArray());
    }

    Console.WriteLine("Press any key to exit program...."); Console.ReadKey();
    } /* end Main */

    static void print(int x)
    {
        Console.WriteLine("Hello World! {0}", x);
        Thread.Sleep(3000);  //Wait 3 seconds to allow other Task to process before exiting
    }
} /* end class */

The results will be similar to what is shown below:结果将类似于如下所示:

Hello World! 2
Hello World! 4
Hello World! 5
Hello World! 1
Hello World! 6

-- A 3 second pause --

Hello World! 8
Hello World! 9
Hello World! 3
Hello World! 10
Hello World! 7

-- A 3 second pause --

Press any key to exit program....

-- Update -- - 更新 -

As mention by Nick, you can also use the Parallel.ForEach method to accomplish the same thing.正如尼克所提到的,您还可以使用 Parallel.ForEach 方法来完成同样的事情。

Example:例子:

Parallel.ForEach (Arr,
    new ParallelOptions { MaxDegreeOfParallelism = maxConcurrency },
    (x) => { print(x); } );

Alternatively, you can use Parallel class and specify MaxDegreeOfParallelism .或者,您可以使用Parallel class 并指定MaxDegreeOfParallelism However, just like the documentation says, normally you will not want to do that.但是,就像文档中所说的那样,通常您不会想要这样做。 See the remarks in the second link.请参阅第二个链接中的备注。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM