Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/263.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# 保持异步运行特定数量的任务_C#_.net_Asynchronous_Concurrency_Task - Fatal编程技术网

C# 保持异步运行特定数量的任务

C# 保持异步运行特定数量的任务,c#,.net,asynchronous,concurrency,task,C#,.net,Asynchronous,Concurrency,Task,我目前正在开发一个并发文件下载程序 出于这个原因,我想参数化并发任务的数量。我不想等待所有的任务都完成,但要保持相同的数字正在运行 事实上,star overflow上的这个线程给了我一个正确的线索,但我正在努力使它异步: 这是我的密码: public async Task StartAsync() { var semaphore = new SemaphoreSlim(1, _concurrentTransfers); var queueHasMessa

我目前正在开发一个并发文件下载程序

出于这个原因,我想参数化并发任务的数量。我不想等待所有的任务都完成,但要保持相同的数字正在运行

事实上,star overflow上的这个线程给了我一个正确的线索,但我正在努力使它异步:

这是我的密码:

public async Task StartAsync()
    {
        var semaphore = new SemaphoreSlim(1, _concurrentTransfers);
        var queueHasMessages = true;

        while (queueHasMessages)
        {
            try {
                await Task.Run(async () =>
                  {
                      await semaphore.WaitAsync();
                      await asyncStuff();
                 });
            }
            finally {
                semaphore.Release();
            };
        }
    }
但是代码一次只执行一个。我认为wait正在阻止我生成所需数量的任务,但我不知道如何避免它,同时遵守信号量建立的限制

如果我将所有任务添加到一个列表中并创建一个whenall,信号量会抛出一个异常,因为它已达到最大计数


有什么建议吗

我注意到,直通解决方案将删除执行期间发生的任何异常。那太糟糕了

以下是一个不会删除异常的解决方案:

Run是创建任务的工厂方法。您可以使用intellisense返回值检查自己。您可以将返回的任务分配到任意位置

wait是一个操作符,它将等待它所操作的任务完成。您可以使用wait操作符执行任何任务

public static async Task RunTasksConcurrently()
{
    IList<Task> tasks = new List<Task>();

    for (int i = 1; i < 4; i++)
    {
        tasks.Add(RunNextTask());
    }

    foreach (var task in tasks) {
        await task; 
    }
}

public static async Task RunNextTask()
{
    while(true) {
        await Task.Delay(500);
    }
}

您可以使用老式的方法轻松地完成这项工作,而无需使用wait by use,它允许您指定要使用的最大并发线程数

例如:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Demo
{
    class Program
    {
        public static void Main(string[] args)
        {
            IEnumerable<string> filenames = Enumerable.Range(1, 100).Select(x => x.ToString());

            Parallel.ForEach(
                filenames,
                new ParallelOptions { MaxDegreeOfParallelism = 4},
                download
            );
        }

        static void download(string filepath)
        {
            Console.WriteLine("Downloading " + filepath);
            Thread.Sleep(1000); // Simulate downloading time.
            Console.WriteLine("Downloaded " + filepath);
        }
    }
}
尝试一下,看看输出中的差异

然而,如果您想要一种更现代的方法来实现这一点,您可以研究-这在异步方法中很有效

这要复杂得多,但要强大得多。你可以用一个例子来做,但是描述如何做超出了我在这里给出的答案的范围

看一看,;它给出了一个简单的例子


还要注意的是,TPL不是内置在.Net中的-您必须从NuGet获得它。

您好!谢谢你的回答。我的问题是如何不断地同时运行N个任务。在您的示例中,我希望运行1,2,3,例如,如果完成3次,则同时运行1,2,4。不做那批taks@AdrianAbreu看看我的编辑是否更接近你想要的。这个解决方案太棒了!我喜欢它的简单。我现在正在努力完成递归循环,但它工作得很顺利@AdrianAbreu为什么您发现递归解决方案比在所有条件{await DoWork;}下编写更简单?当然,您可以编写任何循环,但它不会添加任何内容。whiletrue{wait DoWork;}会在DoWork工作时阻止正在运行的任务。他希望同时运行x个任务,而不是按顺序运行。或者,检查中的自定义任务计划程序。它提供了并发限制,您可以在执行已经开始后向计划程序添加其他任务。您应该将Try&Finally放在正在创建的任务中。由于您在finally中释放信号量,它与wait不一致。
RunNextTask(DataObject object)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Demo
{
    class Program
    {
        public static void Main(string[] args)
        {
            IEnumerable<string> filenames = Enumerable.Range(1, 100).Select(x => x.ToString());

            Parallel.ForEach(
                filenames,
                new ParallelOptions { MaxDegreeOfParallelism = 4},
                download
            );
        }

        static void download(string filepath)
        {
            Console.WriteLine("Downloading " + filepath);
            Thread.Sleep(1000); // Simulate downloading time.
            Console.WriteLine("Downloaded " + filepath);
        }
    }
}
static Random rng = new Random();

static void download(string filepath)
{
    Console.WriteLine("Downloading " + filepath);
    Thread.Sleep(500 + rng.Next(1000)); // Simulate random downloading time.
    Console.WriteLine("Downloaded " + filepath);
}