Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/325.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#_Asynchronous_Async Await - Fatal编程技术网

C# 等待成千上万的任务

C# 等待成千上万的任务,c#,asynchronous,async-await,C#,Asynchronous,Async Await,我有一个应用程序,它可以转换一些数据,通常有1.000-30.000个文件 我需要执行3个步骤: 复制文件(替换其中的一些文本) 使用WebClient发出Webrequest以下载文件(我将复制的文件发送到Web服务器,该服务器将文件转换为其他格式) 获取下载的文件并更改部分内容 因此,这三个步骤都包括一些I/O,我使用了异步/等待方法: var tasks = files.Select(async (file) => { Item item = await createtemp

我有一个应用程序,它可以转换一些数据,通常有1.000-30.000个文件

我需要执行3个步骤:

  • 复制文件(替换其中的一些文本)
  • 使用WebClient发出Webrequest以下载文件(我将复制的文件发送到Web服务器,该服务器将文件转换为其他格式)
  • 获取下载的文件并更改部分内容
  • 因此,这三个步骤都包括一些I/O,我使用了异步/等待方法:

    var tasks = files.Select(async (file) =>
    {
        Item item = await createtempFile(file).ConfigureAwait(false);
        await convert(item).ConfigureAwait(false);
        await clean(item).ConfigureAwait(false);
    }).ToList();
    
    await Task.WhenAll(tasks).ConfigureAwait(false);
    
    我不知道这是否是最佳实践,因为我创建了上千个任务。我考虑将三个步骤分开,如:

    List<Item> items = new List<Item>();
    var tasks = files.Select(async (file) =>
    {
        Item item = await createtempFile(file, ext).ConfigureAwait(false);
        lock(items)
            items.Add(item);
    }).ToList();
    
    await Task.WhenAll(tasks).ConfigureAwait(false);
    
    var tasks = items.Select(async (item) =>
    {
        await convert(item, baseAddress, ext).ConfigureAwait(false);
    }).ToList();
    
    await Task.WhenAll(tasks).ConfigureAwait(false);
    
    var tasks = items.Select(async (item) =>
    {
        await clean(targetFile, item.Doctype, ext).ConfigureAwait(false);
    }).ToList();
    
    await Task.WhenAll(tasks).ConfigureAwait(false);
    
    List items=newlist();
    var任务=文件。选择(异步(文件)=>
    {
    Item Item=await createtempFile(文件,ext).ConfigureAwait(false);
    锁(项目)
    项目。添加(项目);
    }).ToList();
    等待任务.WhenAll(任务).配置等待(false);
    变量任务=项目。选择(异步(项目)=>
    {
    等待转换(项、基地址、分机)。配置等待(false);
    }).ToList();
    等待任务.WhenAll(任务).配置等待(false);
    变量任务=项目。选择(异步(项目)=>
    {
    等待清除(targetFile,item.Doctype,ext).ConfigureAwait(false);
    }).ToList();
    等待任务.WhenAll(任务).配置等待(false);
    
    但这似乎不是更好或更快,因为我创建了3倍于数千个任务

    我应该限制任务的创建吗?比如100个任务的块? 或者我只是想得太多了,而创建数千个任务也很好

    CPU以2-4%的峰值空闲,所以我考虑了太多的等待或上下文切换

    也许WebRequest调用太多了,因为WebServer/WebService不能同时处理数千个请求,我应该只限制WebRequest


    我已经在app.config文件中增加了.NET maxconnection。

    可以并行执行异步操作,同时限制并发操作的数量。有一种很酷的扩展方法,它不是.Net framework的一部分

    /// <summary>
    /// Enumerates a collection in parallel and calls an async method on each item. Useful for making 
    /// parallel async calls, e.g. independent web requests when the degree of parallelism needs to be
    /// limited.
    /// </summary>
    public static Task ForEachAsync<T>(this IEnumerable<T> source, int degreeOfParalellism, Func<T, Task> action)
    {
        return Task.WhenAll(Partitioner.Create(source).GetPartitions(degreeOfParalellism).Select(partition => Task.Run(async () =>
        {
            using (partition)
                while (partition.MoveNext())
                    await action(partition.Current);
        })));
    }
    
    //
    ///并行枚举集合并对每个项调用异步方法。对制作有用
    ///并行异步调用,例如,需要调整并行度时的独立web请求
    ///有限的。
    /// 
    公共静态任务ForEachAsync(此IEnumerable源代码,int degreeOfParallelism,Func操作)
    {
    返回Task.WhenAll(Partitioner.Create(source).GetPartitions(degreeofparallelism).Select(partition=>Task.Run(async()=>
    {
    使用(分区)
    while(partition.MoveNext())
    等待操作(partition.Current);
    })));
    }
    
    可以这样称呼:

    var files = new List<string> {"one", "two", "three"};
    await files.ForEachAsync(5, async file =>
    {
       // do async stuff here with the file
       await Task.Delay(1000);
    });
    
    var files=新列表{“一”、“二”、“三”};
    等待文件。ForEachAsync(5,异步文件=>
    {
    //在这里对文件执行异步操作
    等待任务。延迟(1000);
    });
    
    正如评论者正确指出的那样,你想得太多了。NET运行时在跟踪数千个任务方面绝对没有问题


    但是,您可能需要考虑使用TPL数据流管道,这将使您可以容易地为不同的操作(“块”)在流水线中具有不同的并发级别。< /P>什么问题?您可以使用<代码>并行。Parallel.ForEach包含分区器,以避免执行超出必要范围的任务<代码>等待并不意味着启动线程并并行工作。所以我认为你必须重新思考你的想法,使它成为一个真正的线程化应用程序。@NiyokoYuliawan Parallel.Foreach用于CPU绑定的工作,而不是IO绑定的工作。是的,你想得太多了。任务不是线程。它们是小而便宜的包装,而“千”是微不足道的。谢谢你,我不知道这种实现。我总是用信号量lim来限制我的工作。