利用异步实现进度

  前些时间去面试,遇到面试官问我在一个任务中实现进度效果。

  可能一部分人想到的就是文件上传下载利用js的插件就可以实现了,cs模式也是有相应的插件的去实现,但实际上需求是希望实现某项操作,比如大型数据的计算,可能不是一时半会能完成的,也不能让客户分步骤去完成。

   首先我们要将任务分段,如果是有序的任务,比较好处理,比如批量对某些数据进行操作,那么可以根据数据的条数为总量除以完成数量得到任务执行百分比,如果是无序的,就只能对任务进行分段,根据每段的执行时间做一个任务占比的处理。

   而如何获取这些完成的百分比,有两种方式,一种是利用websocket或者SignalR回传完成的百分比,这个是同步的情况。

   另外一种可以利用异步去实现,这是接下来要介绍的。

   首先我们要创建一个异步线程任务:(ps:SmartThreadPool 智能线程池,可以在NuGet查询添加)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Amib.Threading;

namespace Task
{
    public interface IAsyncTask
    {
        AsyncTaskProgress AsyncTaskProgress { get; set; }

        WorkItemPriority Priority { get; set; }

        string TaskKey { get; set; }

        bool IsAuto { get; set; }

        void Queue();

        void Execute();

        void Prepareing();

        void Processing();

        void Exit();

        void ReStart();

        void Cancel();
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Task
{
    public class AsyncTaskProgress
    {
        public AsyncTaskProgress() { }

        public AsyncTaskProgress(bool isPercentTask, decimal percent, string message)
        {
            IsPercentTask = isPercentTask;
            Percent = percent;
            Message = message;
        }

        public bool IsPercentTask { get; set; }

        public decimal Percent { get; set; }

        public string Message { get; set; }

        public AsyncTaskProgressState State { get; set; }

        public bool IsFinish
        {
            get
            {
                return State == AsyncTaskProgressState.Success
                    || State == AsyncTaskProgressState.Cancel
                    || State == AsyncTaskProgressState.Error;
            }
        }
    }
}

 

将这个调度任务装进异步线程任务池里面,

using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Threading;
using Amib.Threading;

namespace Task
{
    /// <summary>
    /// 创建线程池
    /// </summary>
    public class AsyncTaskPool
    {
        public static Dictionary<string, IAsyncTask> Tasks { get; set; }

        public static SmartThreadPool SmartThreadPool { get; set; }

        public static object Object = new object();

        static AsyncTaskPool()
        {
            Tasks = new Dictionary<string, IAsyncTask>();
            SmartThreadPool = new SmartThreadPool();
        }

        public static IWorkItemResult AddTask(IAsyncTask task)
        {
            lock (Object)
            {
                if (Tasks.ContainsKey(task.TaskKey))
                {
                    if (Tasks[task.TaskKey].AsyncTaskProgress.IsFinish)
                    {
                        Tasks.Remove(task.TaskKey);
                    }
                    else
                    {
                        throw new Exception("该任务已存在!");
                    }
                }
                Tasks.Add(task.TaskKey, task);
                return SmartThreadPool.QueueWorkItem(task.Execute, task.Priority);
            }
        }

        public static IAsyncTask GeTask(string key)
        {
            if (Tasks.ContainsKey(key))
            {
                return Tasks[key];
            }
            else
            {
                throw new Exception("该任务不存在!");
            }
        }

        public static bool Remove(string key)
        {
            if (Tasks.ContainsKey(key))
            {
                return Tasks.Remove(key);
            }

            return true;
        }

        public static bool Cancel(string key)
        {
            if (Tasks.ContainsKey(key))
            {
                Tasks[key].Cancel();
            }

            return Remove(key);
        }
    }
}

 

  

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Amib.Threading;

namespace Task
{
    public class BaseAsyncTask : IAsyncTask
    {


        public BaseAsyncTask(string key, bool isAuto, WorkItemPriority priority = WorkItemPriority.Normal, bool isAutoRecovery = false)
        {
            TaskKey = key;
            IsAuto = isAuto;
            Priority = priority;
            IsAutoRecovery = isAutoRecovery;
        }

        public AsyncTaskProgress AsyncTaskProgress { get; set; }


        public WorkItemPriority Priority { get; set; }

        /// <summary>
        /// 是否在异常的情况下自动重启
        /// </summary>
        public bool IsAutoRecovery { get; set; }

        public string TaskKey { get; set; }


        public bool IsAuto { get; set; }


        public void Queue()
        {
            AsyncTaskPool.AddTask(this);
        }

        public virtual void Execute()
        {

            try
            {
                Prepareing();
                Processing();
            }
            catch (Exception)
            {
                //日志记录异常
                throw;
            }
            finally
            {
                if (IsAuto)
                    Exit(); //这里不能释放,不然100%的时候无法捕捉,需要捕捉到100%的时候去释放
            }
        }

        public void Prepareing()
        {
            Console.WriteLine("开始执行任务...");
        }

        public virtual void Processing() { }

        public void Exit()
        {
            AsyncTaskPool.Remove(this.TaskKey);
        }

        public void ReStart()
        {
            AsyncTaskPool.Cancel(this.TaskKey);
            AsyncTaskPool.AddTask(this);
        }

        public virtual void Cancel()
        {
            AsyncTaskPool.Cancel(this.TaskKey);
        }
    }
}

简单的调用

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Channels;
using System.Text;
using System.Threading;
using Amib.Threading;

namespace Tack
{
    public class DalculateMaxDataTask : BaseAsyncTask
    {
        public DalculateMaxDataTask(string key, bool isAuto, WorkItemPriority priority = WorkItemPriority.Normal, bool isAutoRecovery = false)
            : base(key, isAuto, priority, false)
        {
            AsyncTaskProgress = new AsyncTaskProgress();
        }

        public override void Processing()
        {

            AsyncTaskProgress.Percent = 0;

            Thread.Sleep(2000);
            AsyncTaskProgress.Percent = 10;
            Thread.Sleep(2000);
            AsyncTaskProgress.Percent = 20;

            Thread.Sleep(2000);
            AsyncTaskProgress.Percent = 30;
            Thread.Sleep(2000);
            AsyncTaskProgress.Percent = 100;
        }

    }
}

实际调用以及结果

 

  

posted @ 2018-11-13 15:35  无心风雨的落叶  阅读(455)  评论(0编辑  收藏  举报