c# task添加顺序_如何排队使用C#在后台按顺序执行的委托?

From a game loop i want to start work in the background that should be executed one after another but should not block the game loop.

So ideally a class BackgroundQueue that could be used like this:

BackgroundQueue myQueue = new BackgroundQueue();

//game loop called 60 times per second

void Update()

{

if (somethingHappens)

{

myQueue.Enqueue(() => MethodThatTakesLong(someArguments))

}

}

Is there a ready made class in .NET that works for the scenario? Or does someone know a good example on how to implement the BackgroundQueue class?

A nice to have would be if the class could report whether it's currently doing something and how many delegates are queued up...

解决方案

One solution is from the excellent Threading in C# E-book. In their section on basic structures, the author makes almost exactly what you're looking for in an example.

Follow that link and scroll down to Producer/consumer queue.

In a later section, he addresses that while ConcurrentQueue would work fine too, it performs worse in all cases EXCEPT in highly-concurrent scenarios. But for your low-load case, it may be better just to get something working easily. I don't have personal experience with the claim from the document, but it's there for you to evaluate.

I hope this helps.

Edit2: upon Evk's suggestion (thanks!), the BlockingCollection class looks like what you want. By default it uses a ConcurrentQueue under the hood. I particularly like the CompleteAdding method, as well as the ability to use CancellationTokens with it. "Shutdown" scenarios are not always correctly accounted for when things are blocking, but this does it right IMO.

Edit 3: As requested, a sample of how this would work with a BlockingCollection. I used the foreach and GetConsumingEnumerable to make this even more compact for the consumer side of the problem:

using System.Collections.Concurrent;

private static void testMethod()

{

BlockingCollection myActionQueue = new BlockingCollection();

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.");

}

I added in the Sleep() calls so that you can see that things are added while other things are being consumed. You can also choose to launch any number of that consumer lambda (just call it an Action, then launch the Action multiple times) or the addition loop. And at any time you can call Count on the collection to get the number of tasks that are NOT running. Presumably if that's non-zero, then your producer Tasks are running.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值