c# - 异步执行的排队操作/委托(delegate)

标签 c# asynchronous .net-4.0 delegates

框架中是否有允许我异步执行委托(delegate)队列的东西?

我的意思是我希望委托(delegate)按照他们排队的顺序一次执行一个,但我希望整个过程异步运行。队列也不固定,会定期添加额外的委托(delegate),并应在到达队列顶部后立即处理。

我不需要特别使用 Queue,这只是我描述所需行为的方式。

我可以自己写一些东西来做,但如果有内置的东西我可以改用那会更好。

我简要地查看了 ThreadPool.QueueUserWorkItem,因为它允许按顺序执行,但可以找到一种令人满意的方法来防止一次执行多个。

最佳答案

Is there something in the framework that would allow me to asynchronously execute a queue of delegates?

我会将其实现为自定义任务调度程序。然后,您可以将委托(delegate)作为任务排队并运行,这将为您提供异常处理、取消和 async/await 的所有好处。

使用 BlockingCollection 实现一个按顺序执行委托(delegate)的任务调度程序非常简单。下面的 SerialTask​​SchedulerStephen Toub's StaTaskScheduler 的简化版本:

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Console_21628490
{
    // Test
    class Program
    {
        static async Task DoWorkAsync()
        {
            using (var scheduler = new SerialTaskScheduler())
            {
                var tasks = Enumerable.Range(1, 10).Select(i =>
                    scheduler.Run(() =>
                    {
                        var sleep = 1000 / i;
                        Thread.Sleep(sleep);
                        Console.WriteLine("Task #" + i + ", sleep: " + sleep);
                    }, CancellationToken.None));

                await Task.WhenAll(tasks);
            }
        }

        static void Main(string[] args)
        {
            DoWorkAsync().Wait();
            Console.ReadLine();
        }
    }

    // SerialTaskScheduler
    public sealed class SerialTaskScheduler : TaskScheduler, IDisposable
    {
        Task _schedulerTask;
        BlockingCollection<Task> _tasks;
        Thread _schedulerThread;

        public SerialTaskScheduler()
        {
            _tasks = new BlockingCollection<Task>();

            _schedulerTask = Task.Run(() =>
            {
                _schedulerThread = Thread.CurrentThread;

                foreach (var task in _tasks.GetConsumingEnumerable())
                    TryExecuteTask(task);
            });
        }

        protected override void QueueTask(Task task)
        {
            _tasks.Add(task);
        }

        protected override IEnumerable<Task> GetScheduledTasks()
        {
            return _tasks.ToArray();
        }

        protected override bool TryExecuteTaskInline(
            Task task, bool taskWasPreviouslyQueued)
        {
            return _schedulerThread == Thread.CurrentThread &&
                TryExecuteTask(task);
        }

        public override int MaximumConcurrencyLevel
        {
            get { return 1; }
        }

        public void Dispose()
        {
            if (_schedulerTask != null)
            {
                _tasks.CompleteAdding();
                _schedulerTask.Wait();
                _tasks.Dispose();
                _tasks = null;
                _schedulerTask = null;
            }
        }

        public Task Run(Action action, CancellationToken token)
        {
            return Task.Factory.StartNew(action, token, TaskCreationOptions.None, this);
        }

        public Task Run(Func<Task> action, CancellationToken token)
        {
            return Task.Factory.StartNew(action, token, TaskCreationOptions.None, this).Unwrap();
        }

        public Task<T> Run<T>(Func<Task<T>> action, CancellationToken token)
        {
            return Task.Factory.StartNew(action, token, TaskCreationOptions.None, this).Unwrap();
        }
    }
}

输出:

Task #1, sleep: 1000
Task #2, sleep: 500
Task #3, sleep: 333
Task #4, sleep: 250
Task #5, sleep: 200
Task #6, sleep: 166
Task #7, sleep: 142
Task #8, sleep: 125
Task #9, sleep: 111
Task #10, sleep: 100

关于c# - 异步执行的排队操作/委托(delegate),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21628490/

相关文章:

c# - 无法在 asp.net 中连接托管提供商 MYSQL 数据库

c# - 如何编码包含哈希的路径?

c# - Wcf - 异常前重试 3 次?

javascript - 如何解析 JSON 并将其存储在外部变量中?

c# - 如何使用 LINQ (.NET 4) 执行 DISTINCT 查询?

c# - 等同于 2 个对象 - 每次都不同?

c# - 为什么 string.Split (';' ) 有效但 string.Split (':' ,StringSplitOptions.RemoveEmptyEntries) 无效?

c# - 在 C# 中使用字符串调用方法时出现 "Object does not match target type"

javascript - 如何根据 Javascript/AJAX 数据库调用的结果显示 HTML 模式

javascript - 如何从 javascript 中的嵌套异步函数传播返回值