首页 > 解决方案 > 使用 async-await 并行多线程下载

问题描述

我的 Windows 服务 - C# 中有 100 个要从 Web 下载的多个大文件。要求是一次维护 - 最多 4 个并行 Web 文件下载。

我可以使用异步等待实现并发/并行下载还是必须使用BackgroundWorker进程或线程?async-await 是多线程的吗?请参阅下面使用 async-await 的示例程序:

 static int i = 0;
 
 Timer_tick() {
   while (i < 4) {
     i++;
     model = GetNextModel();
     await Download(model);
   }
 }
 
 private async Download(XYZ model) {
   Task<FilesetResult> t = DoWork(model);
   result = await t;
   //Use Result
 }
 
 private async Task<FilesetResult> Work(XYZ model) {
   fileresult = await api.Download(model.path)
   i--;
   return filesetresult;
 }

标签: c#multithreadingasync-await

解决方案


SemaphoreSlim您可以使用类限制并行运行的异步任务的数量。就像是:

List<DownloadRequest> requests = Enumerable.Range(0, 100).Select(x => new DownloadRequest()).ToList();
using (var throttler = new SemaphoreSlim(4))
{
    Task<DownloadResult>[] downloadTasks = requests.Select(request => Task.Run(async () =>
    {
        await throttler.WaitAsync();
        try
        {
            return await DownloadTaskAsync(request);
        }
        finally
        {
            throttler.Release();
        }
    })).ToArray();
    await Task.WhenAll(downloadTasks);
}

更新:感谢您的评论,已解决的问题。

Update2:动态请求列表的示例解决方案

public class DownloadManager : IDisposable
{
    private readonly SemaphoreSlim _throttler = new SemaphoreSlim(4);

    public async Task<DownloadResult> DownloadAsync(DownloadRequest request)
    {
        await _throttler.WaitAsync();
        try
        {
            return await api.Download(request);
        }
        finally
        {
            _throttler.Release();
        }
    }

    public void Dispose()
    {
        _throttler?.Dispose();
    }
}

推荐阅读