从游戏循环中,我想在后台开始工作,该工作应该一个接一个地执行,但不应阻止游戏循环。
所以理想情况下是一个类BackgroundQueue
可以这样使用:
BackgroundQueue myQueue = new BackgroundQueue();
//game loop called 60 times per second
void Update()
{
if (somethingHappens)
{
myQueue.Enqueue(() => MethodThatTakesLong(someArguments))
}
}
.NET 中是否有适合该场景的现成类?或者有人知道如何实施的一个很好的例子BackgroundQueue
class?
如果类可以报告它当前是否正在做某事以及有多少代表在排队,那就太好了......
一种解决方案来自优秀的C# 中的线程电子书。在关于基本结构的部分中,作者几乎完全符合您的要求在一个例子中.
点击该链接并向下滚动到生产者/消费者队列。
在后面的部分中,他谈到了这一点并发队列也可以很好地工作,除了高并发场景之外,它在所有情况下都表现较差。但对于低负载的情况,让某些东西轻松工作可能会更好。我对文档中的声明没有个人经验,但它可供您评估。
我希望这有帮助。
Edit2:根据 Evk 的建议(谢谢!),阻塞收集类看起来像你想要的。默认情况下,它在底层使用 ConcurrentQueue。我特别喜欢完成添加方法,以及使用 CancellationTokens 的能力。当事情发生阻塞时,“关闭”场景并不总是被正确考虑,但在我看来,这是正确的。
编辑 3:根据要求,提供了如何与 BlockingCollection 一起使用的示例。我用的是foreach
and GetConsumingEnumerable
为了让消费者方面的问题变得更加紧凑:
using System.Collections.Concurrent;
private static void testMethod()
{
BlockingCollection<Action> myActionQueue = new BlockingCollection<Action>();
var consumer = Task.Run(() =>
{
foreach(var item in myActionQueue.GetConsumingEnumerable())
{
item(); // Run the task
}// Exits when the BlockingCollection is marked for no more actions
});
// Add some tasks
for(int i = 0; i < 10; ++i)
{
int captured = i; // Imporant to copy this value or else
myActionQueue.Add(() =>
{
Console.WriteLine("Action number " + captured + " executing.");
Thread.Sleep(100); // Busy work
Console.WriteLine("Completed.");
});
Console.WriteLine("Added job number " + i);
Thread.Sleep(50);
}
myActionQueue.CompleteAdding();
Console.WriteLine("Completed adding tasks. Waiting for consumer completion");
consumer.Wait(); // Waits for consumer to finish
Console.WriteLine("All actions completed.");
}
我添加了 Sleep() 调用,以便您可以看到在消耗其他内容时添加了内容。您还可以选择启动任意数量的consumer
lambda(简称为Action
,然后启动Action
多次)或加法循环。并且您可以随时致电Count
在集合上获取未运行的任务数。据推测,如果该值不为零,则您的生产者任务正在运行。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)