在一次设置最大运行任务时等待多个异步任务

Bre*_*ett 5 c# multithreading asynchronous task-parallel-library async-await

所以我开始尝试理解异步,任务,lambda等等,我无法让它像我想的那样工作.使用下面的代码我希望它能锁定btnDoWebRequest,将未知数量的WebRequests作为任务执行,并且一旦完成所有任务,就解锁btnDoWebRequest.不过,我只想要3或任何数量最多我设置在同一时间运行的任务,这是我从获得的部分有一组任务的只有X同时运行.

但是在以多种方式尝试和修改我的代码之后,它将始终立即跳回并重新启用btnDoWebRequest.当然VS警告我需要等待,目前在".ContinueWith((任务)"和"await Task.WhenAll(requestInfoList .Select(async i =>")中的异步,但似乎无法在哪里工作或如何投入所需的等待.当然,因为我还在学习,所以我很有可能在这一切都错了,整个事情都需要重新设计.所以任何帮助都会非常感激.

谢谢

    private SemaphoreSlim maxThread = new SemaphoreSlim(3);
    private void btnDoWebRequest_Click(object sender, EventArgs e)
    {
        btnDoWebRequest.Enabled = false;
        Task.Factory.StartNew(async () => await DoWebRequest()).Wait();
        btnDoWebRequest.Enabled = true;
    }

    private async Task DoWebRequest()
    {
        List<requestInfo> requestInfoList = new List<requestInfo>();
        for (int i = 0; dataRequestInfo.RowCount - 1 > i; i++)
        {
            requestInfoList.Add((requestInfo)dataRequestInfo.Rows[i].Tag);
        }
        await Task.WhenAll(requestInfoList .Select(async i => 
        {
            maxThread.Wait();
            Task.Factory.StartNew(() =>
            {
                var task = Global.webRequestWork(i);
            }, TaskCreationOptions.LongRunning).ContinueWith((task) => maxThread.Release());
        }));
    }
Run Code Online (Sandbox Code Playgroud)

Ste*_*ary 10

首先,不要Task.Factory.StartNew默认使用.实际上,这应该在async代码中避免.如果需要在后台线程上执行代码,请使用Task.Run.

在您的情况下,没有必要使用Task.Run(或Task.Factory.StartNew).

从最低级别开始,逐步提升.您已经有一个异步的Web请求方法,我将重命名WebRequestAsync为遵循基于任务的异步编程命名准则.

接下来,通过使用异步 API 来限制它SemaphoreSlim:

await maxThread.WaitAsync();
try
{
  await Global.WebRequestWorkAsync(i);
}
finally
{
  maxThread.Release();
}
Run Code Online (Sandbox Code Playgroud)

为每个请求信息执行此操作(请注意,不需要后台线程):

private async Task DoWebRequestsAsync()
{
  List<requestInfo> requestInfoList = new List<requestInfo>();
  for (int i = 0; dataRequestInfo.RowCount - 1 > i; i++)
  {
    requestInfoList.Add((requestInfo)dataRequestInfo.Rows[i].Tag);
  }
  await Task.WhenAll(requestInfoList.Select(async i => 
  {
    await maxThread.WaitAsync();
    try
    {
      await Global.WebRequestWorkAsync(i);
    }
    finally
    {
      maxThread.Release();
    }
  }));
}
Run Code Online (Sandbox Code Playgroud)

最后,从您的UI调用此方法(同样,不需要后台线程):

private async void btnDoWebRequest_Click(object sender, EventArgs e)
{
  btnDoWebRequest.Enabled = false;
  await DoWebRequestsAsync();
  btnDoWebRequest.Enabled = true;
}
Run Code Online (Sandbox Code Playgroud)

总之,只Task.Run在需要时使用; 不要使用Task.Factory.StartNew,也不要使用Wait(await改为使用).我在我的博客上有一个async介绍更多信息.