[英]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.