广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C#如何Task执行任务,等待任务完成
  • 469
分享到

C#如何Task执行任务,等待任务完成

2024-04-02 19:04:59 469人浏览 八月长安
摘要

目录Task执行任务,等待任务完成C# Task任务队列需求基本的Task用法让Task任务按顺序执行使用异步委托解决UI界面卡死问题异步任务队列按顺序执行封装任务队列Task执行任

Task执行任务,等待任务完成

代码:

//任务
Func<int> Funcs = () =>
{
    Console.WriteLine("任务开始");
    return 1 + 1;
};
 
//执行任务
Task<int> printRes = Task.Run(Funcs);
 
//等待任务完成
printRes.GetAwaiter().OnCompleted(() =>
{
    Console.WriteLine("异步执行结果:" + printRes.Result);        
});

运行:

任务开始
异步执行结果:2

C# Task任务队列

需求

众所周知,方法体内代码是从上往下执行的,在我们工作中经常会遇到一些需要延时执行,但又必须按顺序来执行的需求。这要怎么解决呢。微软官方提供的Task api就是专门来解决这个问题的。那么下面就开始吧。

基本的Task用法

新建一个Winfrom项目

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.windows.FORMs;
 
namespace 线程2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 
        private void Form1_Load(object sender, EventArgs e)
        {
            Task task1 = new Task(() =>
            {
                Thread.Sleep(400);
                Console.WriteLine("task1");
            });
            Task task2 = new Task(() =>
            {
                Thread.Sleep(300);
                Console.WriteLine("task2");
            });
            Task task3 = new Task(() =>
            {
                Thread.Sleep(200);
                Console.WriteLine("task3");
            });
            Task task4 = new Task(() =>
            {
                Thread.Sleep(100);
                Console.WriteLine("task4");
            });
            task1.Start();
            task2.Start();
            task3.Start();
            task4.Start();
        }
    }
}

运行:

由于各个任务内部延时不同,最先执行的Task1,反而最后一个执行完,如果既要做延时操作,又要求从任务按顺序执行,要怎么解决呢?

让Task任务按顺序执行

修改代码:

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace 线程2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 
        private List<Task> TaskList = new List<Task>();
 
        private void Form1_Load(object sender, EventArgs e)
        {
            Task task1 = new Task(() =>
            {
                Thread.Sleep(400);
                Console.WriteLine("task1");
            });
            Task task2 = new Task(() =>
            {
                Thread.Sleep(300);
                Console.WriteLine("task2");
            });
            Task task3 = new Task(() =>
            {
                Thread.Sleep(200);
                Console.WriteLine("task3");
            });
            Task task4 = new Task(() =>
            {
                Thread.Sleep(100);
                Console.WriteLine("task4");
            });
 
            TaskList.Add(task1);
            TaskList.Add(task2);
            TaskList.Add(task3);
            TaskList.Add(task4);
 
            foreach (Task task in TaskList)
            {
                task.Start();
                task.Wait();
            }
        }
    }
}

运行:

用上面的方法虽然有效,你可以看看,点击界面的时候,界面处鼠标指针会一直转圈,导致winfrom界面卡住,无法操作,这是因为使用Thread.Sleep 导致主线程阻塞,下面就来解决UI界面卡死的问题。

使用异步委托解决UI界面卡死问题

代码:

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace 线程2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 
 
        private List<Task> TaskList = new List<Task>();
 
 
        private void Button_Calculate_Click(object sender, EventArgs e)
        {
            Task task1 = new Task(async () =>
            {
                await Task.Delay(TimeSpan.FromSeconds(4));
                Console.WriteLine("task1");
            });
            Task task2 = new Task(async () =>
            {
                await Task.Delay(TimeSpan.FromSeconds(3));
                Console.WriteLine("task2");
            });
            Task task3 = new Task(async () =>
            {
                await Task.Delay(TimeSpan.FromSeconds(2));
                Console.WriteLine("task3");
            });
            Task task4 = new Task(async () =>
            {
                await Task.Delay(TimeSpan.FromSeconds(1));
                Console.WriteLine("task4");
            });
 
            TaskList.Add(task1);
            TaskList.Add(task2);
            TaskList.Add(task3);
            TaskList.Add(task4);
 
            foreach (Task task in TaskList)
            {
                task.Start();
                task.Wait();
            }
        }
    }
}

运行:

用异步方式虽然界面不会卡住,但另一个问题来了,task.wait()方法似乎没有效果。里面的任务队列依然没有按顺序来执行。那么如何即使用异步执行,也不阻塞主线程,而且要任务按顺序来执行呢?

异步任务队列按顺序执行

代码:

private void Test()
{
    Task.Run(() =>
    {
        Task t1 = new Task(() => {
            Thread.Sleep(2000);
            Console.WriteLine("t1");
            num = 1;
        });
        t1.Start();
        t1.Wait();
        Task t2 = new Task(() => {
            Thread.Sleep(1000);
            Console.WriteLine("t2");
            num = 3;
        });
        t2.Start();
        t2.Wait();
        Console.WriteLine("线程执行完毕");
    });
}

运行:

效果是实现了,代码看起来好搓啊,强迫症都犯了,没关系,可以使用更优雅的写法:

private async void Test()
{
    await Task.Run(async () =>
    {
        await Task.Delay(4000);
        Trace.WriteLine("第1个线程执行");
    });
    await Task.Run(async () =>
    {
        await Task.Delay(3000);
        Trace.WriteLine("第2个线程执行");
    });
    await Task.Run(async () =>
    {
        await Task.Delay(2000);
        Trace.WriteLine("第3个线程执行");
    });
}

运行:

到此为止,功能就实现了,这个需求在Unity3D中使用协程很简单的几句就可以搞定,但在Winfrom等项目的开发中,确实有点繁琐。

封装任务队列

下面的代码我不认为是一个很好的写法,需要添加任务后,还得手动去调用,如果能添加到任务队列就不管了,让其自己自动按顺序来执行任务,岂不是更好,读者如果有兴趣自己去完善这个猜想。另外,在游戏开发中,比如RGP项目中,有专门的任务系统,它和我这个帖子的概念不能混为一谈,RPG任务系统更多的偏向数据的存取,来获取任务的完成状态。

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
 
namespace Utils
{
    public class TaskQueue
    {
        /// <summary>
        /// 任务列表
        /// </summary>
        private List<Task> TaskList = null;
        /// <summary>
        /// 是否在执行任务中
        /// </summary>
        private bool isPerformTask = false;
        /// <summary>
        /// 执行完任务的回调
        /// </summary>
        public Action CallBack = null;
 
 
        private static TaskQueue _instance = null;
        public static TaskQueue Instance
        {
            get
            {
                if (_instance == null)
                    _instance = new TaskQueue();
                return _instance;
            }
        }
 
        /// <summary>
        /// 添加任务
        /// </summary>
        /// <param name="task"></param>
        public void AddTask(Task task)
        {
            if (isPerformTask)
            {
                Console.WriteLine("[TaskQueue]任务正在执行中,此时不能做赋值操作");
                return;
            }
 
            if (task != null)
            {
                TaskList.Add(task);
            }
        }
 
        /// <summary>
        /// 执行任务
        /// </summary>
        public void PerformTask()
        {
            if (isPerformTask)
            {
                Console.WriteLine("[TaskQueue]任务正在执行中,不可重复调用");
                return;
            }
            if (TaskList == null || TaskList.Count == 0)
            {
                Console.WriteLine("[TaskQueue]任务列表为空");
                return;
            }         
 
            Task.Run(() =>
            {
                isPerformTask = true;
 
                foreach (Task item in TaskList)
                {
                    item.Start();
                    item.Wait();
                }
 
                TaskList.Clear();
                isPerformTask = false;
 
                if (CallBack != null) CallBack();
            });
        }
 
        private TaskQueue()
        {
            TaskList = new List<Task>();
        }
    }
}

调用:

Task task1 = new Task(() =>
{
    Thread.Sleep(1000);
    Console.WriteLine("t1");
});
Task task2 = new Task(() =>
{
    Thread.Sleep(2000);
    Console.WriteLine("t2");
});
Task task3 = new Task(() =>
{
    Console.WriteLine("t3");
});
Action callback = () =>
{
    Console.WriteLine("所有任务执行完成");
};
TaskQueue.Instance.AddTask(task1);
TaskQueue.Instance.AddTask(task2);
TaskQueue.Instance.AddTask(task3);
TaskQueue.Instance.CallBack = callback;
TaskQueue.Instance.PerformTask();

运行:

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。 

--结束END--

本文标题: C#如何Task执行任务,等待任务完成

本文链接: https://www.lsjlt.com/news/150959.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C#如何Task执行任务,等待任务完成
    目录Task执行任务,等待任务完成C# Task任务队列需求基本的Task用法让Task任务按顺序执行使用异步委托解决UI界面卡死问题异步任务队列按顺序执行封装任务队列Task执行任...
    99+
    2022-11-13
  • C#怎么Task执行任务
    本篇内容介绍了“C#怎么Task执行任务”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Task执行任务,等待任务完成代码://任务Func&...
    99+
    2023-07-02
  • C#怎么使用Task实现执行并行任务
    这篇“C#怎么使用Task实现执行并行任务”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“C#怎么使用Task实现执行并行任务...
    99+
    2023-07-05
  • java如何防止定时任务未执行完成
    在Java中,可以使用以下几种方法来防止定时任务未执行完成:1. 使用线程池:可以使用Java提供的线程池来执行定时任务,通过设置线...
    99+
    2023-08-29
    java
  • Linux如何执行shell脚本完成任务计划
    小编给大家分享一下Linux如何执行shell脚本完成任务计划,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!导读众所周知,当前linux跑任务计划我们一般借助于crontab任务计划来实现。但这个任务计划默认最小单位为分钟...
    99+
    2023-06-05
  • Spring Task如何动态修改任务执行计划cron
    小编给大家分享一下Spring Task如何动态修改任务执行计划cron,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!Spring Task 动态修改任务执行计划...
    99+
    2023-06-25
  • Java中如何判断线程池任务已执行完成
    目录不判断的问题方法1:isTerminated缺点分析扩展:线程池的所有状态方法2:getCompletedTaskCount方法说明优缺点分析方法3:CountDownLatch...
    99+
    2022-11-13
  • C#使用Task实现执行并行任务的原理的示例详解
    目录一、Task执行并行任务的原理二、5个示例展示示例1示例2示例3示例4示例5三、使用async/await关键字注意示例1示例2四、总结一、Task执行并行任务的原理 使用Tas...
    99+
    2023-05-14
    C# Task执行并行任务 C# Task并行任务 C# Task
  • java如何定时执行任务
    java如何定时执行一个方法java实现定时功能有多种方式,下面介绍3种:1、创建一个线程.import java.util.Date; public class ThreadTest { public static void ma...
    99+
    2022-04-07
    java基础 java 定时
  • Python中如何执行SQL任务
    Python中如何执行SQL任务,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。导入数据  你可以导入.sql数据库并用SQL查询中处理它们...
    99+
    2022-10-18
  • 如何使用spring-task定时任务动态配置修改执行时间
    小编给大家分享一下如何使用spring-task定时任务动态配置修改执行时间,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!spring-task定时任务动态配置修改执行时间因项目需要,几个定时任务需要人为动态设置执行时间,...
    99+
    2023-06-25
  • quartz任务不执行如何排查
    要排查Quartz任务为何不执行,可以采取以下步骤:1. 检查任务调度器的状态:确保任务调度器已经启动,并且没有出现任何错误或异常。...
    99+
    2023-09-13
    quartz
  • for循环内线程池并发执行任务,等到子线程全部处理完任务,主线程在执行java的实现方式
    for循环内线程池并发执行任务,等到子线程全部处理完任务,主线程在执行 方式一 使用 CountDownLatch 在 Java 中,您可以使用 CountDownLatch 来实现主线程等待子线程执行完成的功能。CountDownLatc...
    99+
    2023-08-23
    多线程 线程池 线程调用顺序
  • Linux如何定时执行任务教程
    目录1 教程1.1 安装crontabs1.2 查看crontab服务的状态:1.3 查看crontab的日志信息1.4 配置定时任务(1)修改定时任务:(2)查看定时任务1.5 crontab命令详解1.5.1 命令格...
    99+
    2023-04-23
    Linux定时任务教程 Linux定时任务 Linux任务
  • Java循环屏障中CyclicBarrier如何实现多线程分段等待执行完成
    Java循环屏障中CyclicBarrier如何实现多线程分段等待执行完成,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。前言工作中是否有这样的场景,多个线程任务...
    99+
    2023-06-25
  • 如何处理Go语言中的并发任务的任务调度和任务执行报告问题?
    如何处理Go语言中的并发任务的任务调度和任务执行报告问题?引言:并发任务的任务调度和任务执行报告是Go语言中常见的问题之一。在实际开发中,我们经常需要同时处理多个任务,但是如何高效地调度和执行这些任务,并且能够准确地知道任务的执行情况,对于...
    99+
    2023-10-22
    并发任务调度 并发任务执行报告 Go语言中的处理方法
  • win10计划任务不执行如何解决
    如果Windows 10计划任务不执行,可以尝试以下方法解决:1. 检查计划任务设置:打开“任务计划程序库”,找到相应的计划任务,检...
    99+
    2023-10-10
    win10
  • CentOS7如何执行PHP定时任务详解
    前言 本文主要给大家介绍了关于CenomZhJTPtOS7执行php定时任务的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧 一、CentOS 7 安装crontab: yum instal...
    99+
    2022-06-04
    centos 定时执行任务 php定时执行任务 服务器执行php任务
  • Java 详解循环屏障CyclicBarrier如何实现多线程分段等待执行完成
    前言 工作中是否有这样的场景,多个线程任务,如果所有线程完成到某个阶段,你希望知道所有线程均完成该阶段。当然你使用线程计数可以实现,只是不够优雅。 所以我即:Java 多线程等待优雅...
    99+
    2022-11-12
  • Django中如何使用django-celery完成异步任务
    这期内容当中小编将会给大家带来有关Django中如何使用django-celery完成异步任务 ,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Django中如何使用django-celery完成异步任务&...
    99+
    2023-06-04
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作