繁体   English   中英

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

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

我想并行运行 3 个任务,这些任务将在 for 循环中从一个大小为 n 的数组中获取输入。 一旦完成一项任务,它将从数组中获取另一个输入,依此类推。

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

如果您有任何其他建议,那么欢迎您。

您的代码的问题是您有两个等待语句,一个是阻塞的,一个是非阻塞的。

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

您只需要等待一次可用的信号量。 因此,如果您注释掉 concurrencySemaphore.Wait() 行,您的代码将按预期工作。

关于您的代码的其他注意事项:

由于您只为异步处理指定了一种方法(WaitAsync 方法),因此如果您将 WaitAsync 替换为 Wait,此代码将运行完全相同。 因此,在这种情况下使用 WaitAsync 时,任务将首先执行 WaitAsync 方法,如果它无法输入信号量,它将暂停该语句并执行另一个异步语句。 但是由于没有定义更多的异步方法,代码最终会阻塞,直到它可以输入信号量。

为了证明您的代码一次处理 5 个任务,您应该在 PRINT function 中添加对 Sleep 方法的调用。 这将允许您在任何给定时间直观地查看正在处理的任务数量。

例子:

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
}

此处演示的是代码的调整版本,其中 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 */

结果将类似于如下所示:

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....

- 更新 -

正如尼克所提到的,您还可以使用 Parallel.ForEach 方法来完成同样的事情。

例子:

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

或者,您可以使用Parallel class 并指定MaxDegreeOfParallelism 但是,就像文档中所说的那样,通常您不会想要这样做。 请参阅第二个链接中的备注。

暂无
暂无

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

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