C# 实现异步队列中等待await执行完毕再执行下一个任务

普通的异步队列可以回看我之前一篇博客:https://www.cnblogs.com/log9527blog/p/16517315.html

但是之前实现的异步队列中,任务如果出现await等待,会认为该任务已经完成,并且开始下一个任务。所有为了实现异步队列中等待await执行完毕再执行下一个任务,下面重写了新的异步队列:

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

namespace Text
{
    /// <summary>
    /// 异步任务队列
    /// <para>同步执行,等待委托内的await完成再执行下一个委托,并且自动取消中间的任务</para>
    /// </summary>
    public class SynchronizeTaskQueue
    {
        #region 执行

        /// <summary>
        /// 执行多个同步操作(同步执行,取消中间未执行的任务,传进来的委托需要try...catch...)
        /// </summary>
        /// <param name="func">异步操作</param>
        public void ExecuteFromResult(Func<Task> func)
        {
            AddPendingAwaitTaskToQueue(func);
            Task.Run(async () =>
            {
                await ExcuteTaskQueue();
            });
        }

        #endregion

        #region 添加任务

        /// <summary>
        /// 添加待执行任务到队列
        /// </summary>
        /// <param name="func"></param>
        /// <returns></returns>
        private void AddPendingAwaitTaskToQueue(Func<Task> func)
        {
            // 添加队列,加锁。
            lock (_funcQueue)
            {
                // 添加任务
                _funcQueue.Enqueue(func);
                var newTask = new Task<Task>(async () =>
                {
                    await InternalAwaitRunning();
                });
                _taskQueue.Enqueue(newTask);
            }
        }

        /// <summary>
        /// 执行队列任务
        /// </summary>
        /// <returns></returns>
        private async Task ExcuteTaskQueue()
        {
            try
            {
                await _semaphoreSlim.WaitAsync();
                var count = _taskQueue.Count;
                Task<Task> task = null;
                for (int i = 0; i < count; i++)
                {
                    // 移出所有的线程,并且只执行最后一个
                    _taskQueue.TryDequeue(out task);

                    // 移出中间不执行的委托
                    if (i < count - 1)
                    {
                        _funcQueue.TryDequeue(out Func<Task> func);
                    }
                }

                if (task == null) return;
                task.Start();
                await await task;
            }
            finally
            {
                _semaphoreSlim.Release();
            }
        }

        #endregion

        #region 内部运行

        /// <summary>
        /// 执行委托
        /// </summary>
        /// <returns></returns>
        private async Task InternalAwaitRunning()
        {
            if (TryGetNextAwaitTask(out var func))
            {
                await func();
            }
        }
        
        /// <summary>
        /// 获取
        /// </summary>
        /// <param name="func"></param>
        /// <returns></returns>
        private bool TryGetNextAwaitTask(out Func<Task> func)
        {
            func = null;
            while (_funcQueue.Count > 0)
            {
                //获取并从队列中移除任务
                if (_funcQueue.TryDequeue(out func))
                {
                    return true;
                }
            }

            return false;
        }

        #endregion

        #region 属性及字段

        /// <summary>
        /// 控制当出现多个任务在队列中时,限制等待上一个任务执行完成才到下一个
        /// </summary>
        private readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1);

        /// <summary>
        /// 线程队列
        /// </summary>
        private readonly ConcurrentQueue<Task<Task>> _taskQueue = new ConcurrentQueue<Task<Task>>();

        /// <summary>
        /// 委托队列
        /// </summary>
        private readonly ConcurrentQueue<Func<Task>> _funcQueue = new ConcurrentQueue<Func<Task>>();

        #endregion
    }
}

上面的异步队列会同步执行,并且自动取消中间未执行的任务。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值