C# 如何正确使用Async、Wait和ManualResetEvents来控制无限while循环
所以我在这里要做的是:C# 如何正确使用Async、Wait和ManualResetEvents来控制无限while循环,c#,multithreading,asynchronous,async-await,manualresetevent,C#,Multithreading,Asynchronous,Async Await,Manualresetevent,所以我在这里要做的是: 如果队列不是空的,则使引擎循环并处理对象 如果队列为空,我调用manualresetevent使线程休眠 当添加项目且循环未激活时,我设置ManualReset事件 为了加快速度,我从列表中选择atmost 5项,并对它们异步执行操作,然后等待它们全部完成 问题: 调用AddToUpdateQueueMethod的新调用后,将立即调用这两个列表上的clear方法 在我的脑海中,当我在等待任务时。WhenAll(任务),所以线程应该等待它的完成,然后再继续,因此列表上的cl
public async Task ThumbnailUpdaterEngine()
{
int count;
List<Task<bool>> tasks = new List<Task<bool>>();
List<Content> candidateContents = new List<Content>();
while (true)
{
for (int i = 0; i < 5; i++)
{
Content nextContent = GetNextFromInternalQueue();
if (nextContent == null)
break;
else
candidateContents.Add(nextContent);
}
foreach (var candidateContent in candidateContents)
{
foreach (var provider in interactionProviders)
{
if (provider.IsServiceSupported(candidateContent.ServiceType))
{
Task<bool> task = provider.UpdateThumbnail(candidateContent);
tasks.Add(task);
break;
}
}
}
var results = await Task.WhenAll(tasks);
tasks.Clear();
foreach (var candidateContent in candidateContents)
{
if (candidateContent.ThumbnailLink != null && !candidateContent.ThumbnailLink.Equals(candidateContent.FileIconLink, StringComparison.CurrentCultureIgnoreCase))
{
Task<bool> task = DownloadAndUpdateThumbnailCache(candidateContent);
tasks.Add(task);
}
}
await Task.WhenAll(tasks);
//Clean up for next time the loop comes in.
tasks.Clear();
candidateContents.Clear();
lock (syncObject)
{
count = internalQueue.Count;
if (count == 0)
{
isQueueControllerRunning = false;
monitorEvent.Reset();
}
}
await Task.Run(() => monitorEvent.WaitOne());
}
}
private Content GetNextFromInternalQueue()
{
lock (syncObject)
{
Content nextContent = null;
if (internalQueue.Count > 0)
{
nextContent = internalQueue[0];
internalQueue.Remove(nextContent);
}
return nextContent;
}
}
public void AddToUpdateQueue(Content content)
{
lock (syncObject)
{
internalQueue.Add(content);
if (!isQueueControllerRunning)
{
isQueueControllerRunning = true;
monitorEvent.Set();
}
}
}
public异步任务ThumbnailUpdaterEngine()
{
整数计数;
列表任务=新列表();
List candidateContents=新列表();
while(true)
{
对于(int i=0;i<5;i++)
{
Content-nextContent=GetNextFromInternalQueue();
if(nextContent==null)
打破
其他的
候选内容。添加(下一个内容);
}
foreach(candidateContent中的var candidateContent)
{
foreach(interactionProviders中的变量提供程序)
{
if(provider.IsServiceSupported(candidateContent.ServiceType))
{
Task Task=provider.UpdateThumbnail(candidateContent);
任务。添加(任务);
打破
}
}
}
var结果=等待任务.WhenAll(任务);
任务。清除();
foreach(candidateContent中的var candidateContent)
{
if(candidateContent.ThumbnailLink!=null&!candidateContent.ThumbnailLink.Equals(candidateContent.FileIconLink,StringComparison.CurrentCultureIgnoreCase))
{
任务任务=下载并更新HumbnailCache(候选内容);
任务。添加(任务);
}
}
等待任务。何时(任务);
//为下一次循环进入清理。
任务。清除();
candidateContents.Clear();
锁定(同步对象)
{
count=internalQueue.count;
如果(计数=0)
{
isQueueControllerRunning=false;
monitoreport.Reset();
}
}
wait Task.Run(()=>monitorEvent.WaitOne());
}
}
私有内容GetNextFromInternalQueue()
{
锁定(同步对象)
{
Content nextContent=null;
如果(internalQueue.Count>0)
{
nextContent=internalQueue[0];
internalQueue.Remove(nextContent);
}
返回下一个内容;
}
}
public void AddToUpdateQueue(内容)
{
锁定(同步对象)
{
添加(内容);
如果(!isQueueControllerRunning)
{
isQueueControllerRunning=true;
monitorepent.Set();
}
}
}
您只需使用TPL数据流即可。它是TPL之上的一个actor框架,支持async
。将ActionBlock
与async
操作和MaxDegreeOfParallelism
一起使用5:
var block = new ActionBlock<Content>(
async content =>
{
var tasks = interactionProviders.
Where(provider => provider.IsServiceSupported(content.ServiceType)).
Select(provider => provider.UpdateThumbnail(content));
await Task.WhenAll(tasks);
if (content.ThumbnailLink != null && !content.ThumbnailLink.Equals(
content.FileIconLink,
StringComparison.CurrentCultureIgnoreCase))
{
await DownloadAndUpdateThumbnailCache(content);
}
}, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 5});
使用TPL,您几乎不需要使用
ManualResetEvent
和类似Task.Run(()=>monitorent.WaitOne())
,除非您处理一些遗留代码。看看TPL数据流,它提供了很多用于组织管道处理的功能。您要寻找的是一个,这样就可以处理while循环的内部结构,但是如何使while循环在队列为空时休眠,并且仅在队列有内容时才唤醒。我可以使用wait Task.Sleep(someTimeout),但这不是最佳选择。除了块初始化之外,上面的代码将进入while循环,但是如何控制while循环线程。@Jack_2060您不需要这样做。TPL数据流为您处理所有这些。它有5个任务在内部对您的内容运行委托,当任务完成且队列为空时,任务完成。下次发布到块时,将创建一个新任务,以此类推。
foreach (var content in GetContent())
{
block.Post(content);
}
block.Complete();
await block.Completion