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介绍更多信息.