当前位置: 移动技术网 > IT编程>开发语言>c# > C#线程学习笔记十:async & await入门三

C#线程学习笔记十:async & await入门三

2019年12月18日  | 移动技术网IT编程  | 我要评论

    一、task.yield

    task.yield简单来说就是创建时就已经完成的task,或者说执行时间为0的task,或者说是空任务,也就是在创建时就将task的iscompeted值设置为0。

    我们知道await的task完成时会释放线程,然后从线程池中申请新的线程继续执行await之后的代码,那产生的空任务又意义何在呢?

    事实上,task.yield产生的空任务仅仅是借await做嫁衣来达到线程切换的目的,即让await之后的操作重新去线程池排队申请新线程来继续执行。

    这样一来,假如有一个优先级低但执行时间长的任务,可以将它拆分成多个小任务,每个小任务执行完成后就重新去线程池中排队申请新线程来执行

下一个小任务,这样任务就不会一直霸占着某个线程了(出让执行权),让别的优先急高或执行时间短的任务可以去执行,而不是干瞪眼着急。

    class program
    {
        static void main(string[] args)
        {
            #region async & await入门三之task.yield 
            const int num = 10000;
            var task = yieldpertimes(num);

            for (int i = 0; i < 10; i++)
            {
                task.factory.startnew(n => loop((int)n), num / 10);
            }

            console.writeline($"sum: {task.result}");
            console.read();
            #endregion
        }

        /// <summary>
        /// 循环
        /// </summary>
        /// <param name="num"></param>
        private static void loop(int num)
        {
            for (var i = 0; i < num; i++) ;
            console.writeline($"loop->current thread id is:{thread.currentthread.managedthreadid}");
            thread.sleep(10);
        }

        /// <summary>
        /// 分批出让执行权
        /// </summary>
        /// <param name="times"></param>
        /// <returns></returns>
        private static async task<int> yieldpertimes(int num)
        {
            var sum = 0;
            for (int i = 1; i <= num; i++)
            {
                sum += i;
                if (i % 1000 == 0)
                {
                    console.writeline($"yield->current thread id is:{thread.currentthread.managedthreadid}");
                    thread.sleep(10);
                    await task.yield();
                }
            }
            return sum;
        }
    }

    运行结果如下:

    二、在winform中使用异步lambda表达式

        public main()
        {
            initializecomponent();

            //异步表达式:async (sender, e)
            btndoit.click += async (sender, e) =>
            {
                doit(false, "开始搬砖啦...");
                await task.delay(3000);
                doit(true, "终于搬完了。");
            };
        }

        private void doit(bool isenable, string text)
        {
            btndoit.enabled = isenable;
            lbltext.text = text;
        }

    运行结果如下:

    三、滚动条应用

        private cancellationtokensource source;
        private cancellationtoken token;

        public processbar()
        {
            initializecomponent();
        }

        /// <summary>
        /// 初始化
        /// </summary>
        private void inittool()
        {
            progressbar1.value = 0;
            btndoit.enabled = true;
            btncancel.enabled = true;
        }

        /// <summary>
        /// 开始任务
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void btndoit_click(object sender, eventargs e)
        {
            btndoit.enabled = false;

            source = new cancellationtokensource();
            token = source.token;

            var completedpercent = 0;               //完成百分比
            const int looptimes = 10;               //循环次数
            const int increment = 100 / looptimes;  //进度条每次增加的进度值

            for (var i = 1; i <= looptimes; i++)
            {
                if (token.iscancellationrequested)
                {
                    break;
                }

                try
                {
                    await task.delay(200, token);
                    completedpercent = i * increment;
                }
                catch (exception)
                {
                    completedpercent = i * increment;
                }
                finally
                {
                    progressbar1.value = completedpercent;
                }
            }

            var msg = token.iscancellationrequested ? $"任务被取消,已执行进度为:{completedpercent}%。" : $"任务执行完成。";
            messagebox.show(msg, "提示", messageboxbuttons.ok, messageboxicon.information);

            progressbar1.value = 0;
            inittool();
        }

        /// <summary>
        /// 取消任务
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btncancel_click(object sender, eventargs e)
        {
            if (btndoit.enabled) return;

            btncancel.enabled = false;
            source.cancel();
        }
    }

    运行结果如下:

    四、backgroundworker

    与async & await不同的是,有时候可能需要一个额外的线程,它在后台持续完成某个任务并不时与主线程通信,这时就需要用到backgroundworker类。

(主要用于gui程序)

        private readonly backgroundworker bgworker = new 
        backgroundworker();

        public processbar()
        {
            initializecomponent();

            //设置backgroundworker属性
            bgworker.workerreportsprogress = true;      //能否报告进度更新
            bgworker.workersupportscancellation = true; //是否支持异步取消

            //连接backgroundworker对象的处理程序
            bgworker.dowork += bgworker_dowork;
            bgworker.progresschanged += bgworker_progresschanged;
            bgworker.runworkercompleted += bgworker_runworkercompleted;
        }

        /// <summary>
        /// 开始执行后台操作触发,即调用backgroundworker.runworkerasync时发生。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void bgworker_dowork(object sender, doworkeventargs e)
        {
            if (!(sender is backgroundworker worker))
            {
                return;
            }

            for (var i = 1; i <= 10; i++)
            {
                //判断程序是否已请求取消后台操作
                if (worker.cancellationpending)
                {
                    e.cancel = true;
                    break;
                }

                worker.reportprogress(i * 10);  //触发backgroundworker.progresschanged事件
                thread.sleep(200);              //线程挂起200毫秒
            }
        }

        /// <summary>
        /// 调用backgroundworker.reportprogress(system.int32)时发生
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void bgworker_progresschanged(object sender, progresschangedeventargs e)
        {
            progressbar1.value = e.progresspercentage;  //异步任务的进度百分比
        }

        /// <summary>
        /// 当后台操作已完成或被取消或引发异常时发生
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void bgworker_runworkercompleted(object sender, runworkercompletedeventargs e)
        {
            messagebox.show(e.cancelled ? $@"任务已被取消,已执行进度为:{progressbar1.value}%" : $@"任务执行完成,已执行进度为:{progressbar1.value}%");
            progressbar1.value = 0;
        }

        /// <summary>
        /// 开始任务
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btndoit_click(object sender, eventargs e)
        {
            //判断backgroundworker是否正在执行异步操作
            if (!bgworker.isbusy)
            {
                bgworker.runworkerasync();  //开始执行后台操作
            }
        }

        /// <summary>
        /// 取消任务
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btncancel_click(object sender, eventargs e)
        {
            bgworker.cancelasync(); //请求取消挂起的后台操作
        }

    运行结果如下:

    参考自:

    

    

    后记:

    关于更详细的backgroundworker知识,可查看此篇博客:

    

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网