欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#如何Task執(zhí)行任務(wù),等待任務(wù)完成

 更新時(shí)間:2022年06月09日 10:33:09   作者:熊思雨  
這篇文章主要介紹了C#如何Task執(zhí)行任務(wù),等待任務(wù)完成,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

Task執(zhí)行任務(wù),等待任務(wù)完成

代碼:

//任務(wù)
Func<int> Funcs = () =>
{
? ? Console.WriteLine("任務(wù)開(kāi)始");
?? ?return 1 + 1;
};
?
//執(zhí)行任務(wù)
Task<int> printRes = Task.Run(Funcs);
?
//等待任務(wù)完成
printRes.GetAwaiter().OnCompleted(() =>
{
? ? Console.WriteLine("異步執(zhí)行結(jié)果:" + printRes.Result); ? ? ? ?
});

運(yùn)行:

任務(wù)開(kāi)始
異步執(zhí)行結(jié)果:2

C# Task任務(wù)隊(duì)列

需求

眾所周知,方法體內(nèi)代碼是從上往下執(zhí)行的,在我們工作中經(jīng)常會(huì)遇到一些需要延時(shí)執(zhí)行,但又必須按順序來(lái)執(zhí)行的需求。這要怎么解決呢。微軟官方提供的Task API就是專門(mén)來(lái)解決這個(gè)問(wèn)題的。那么下面就開(kāi)始吧。

基本的Task用法

新建一個(gè)Winfrom項(xiàng)目

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();
        }
    }
}

運(yùn)行:

由于各個(gè)任務(wù)內(nèi)部延時(shí)不同,最先執(zhí)行的Task1,反而最后一個(gè)執(zhí)行完,如果既要做延時(shí)操作,又要求從任務(wù)按順序執(zhí)行,要怎么解決呢?

讓Task任務(wù)按順序執(zhí)行

修改代碼:

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();
            }
        }
    }
}

運(yùn)行:

用上面的方法雖然有效,你可以看看,點(diǎn)擊界面的時(shí)候,界面處鼠標(biāo)指針會(huì)一直轉(zhuǎn)圈,導(dǎo)致winfrom界面卡住,無(wú)法操作,這是因?yàn)槭褂肨hread.Sleep 導(dǎo)致主線程阻塞,下面就來(lái)解決UI界面卡死的問(wèn)題。

使用異步委托解決UI界面卡死問(wèn)題

代碼:

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();
            }
        }
    }
}

運(yùn)行:

用異步方式雖然界面不會(huì)卡住,但另一個(gè)問(wèn)題來(lái)了,task.wait()方法似乎沒(méi)有效果。里面的任務(wù)隊(duì)列依然沒(méi)有按順序來(lái)執(zhí)行。那么如何即使用異步執(zhí)行,也不阻塞主線程,而且要任務(wù)按順序來(lái)執(zhí)行呢?

異步任務(wù)隊(duì)列按順序執(zhí)行

代碼:

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("線程執(zhí)行完畢");
    });
}

運(yùn)行:

效果是實(shí)現(xiàn)了,代碼看起來(lái)好搓啊,強(qiáng)迫癥都犯了,沒(méi)關(guān)系,可以使用更優(yōu)雅的寫(xiě)法:

private async void Test()
{
    await Task.Run(async () =>
    {
        await Task.Delay(4000);
        Trace.WriteLine("第1個(gè)線程執(zhí)行");
    });
    await Task.Run(async () =>
    {
        await Task.Delay(3000);
        Trace.WriteLine("第2個(gè)線程執(zhí)行");
    });
    await Task.Run(async () =>
    {
        await Task.Delay(2000);
        Trace.WriteLine("第3個(gè)線程執(zhí)行");
    });
}

運(yùn)行:

到此為止,功能就實(shí)現(xiàn)了,這個(gè)需求在Unity3d中使用協(xié)程很簡(jiǎn)單的幾句就可以搞定,但在Winfrom等項(xiàng)目的開(kāi)發(fā)中,確實(shí)有點(diǎn)繁瑣。

封裝任務(wù)隊(duì)列

下面的代碼我不認(rèn)為是一個(gè)很好的寫(xiě)法,需要添加任務(wù)后,還得手動(dòng)去調(diào)用,如果能添加到任務(wù)隊(duì)列就不管了,讓其自己自動(dòng)按順序來(lái)執(zhí)行任務(wù),豈不是更好,讀者如果有興趣自己去完善這個(gè)猜想。另外,在游戲開(kāi)發(fā)中,比如RGP項(xiàng)目中,有專門(mén)的任務(wù)系統(tǒng),它和我這個(gè)帖子的概念不能混為一談,RPG任務(wù)系統(tǒng)更多的偏向數(shù)據(jù)的存取,來(lái)獲取任務(wù)的完成狀態(tài)。

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
 
namespace Utils
{
    public class TaskQueue
    {
        /// <summary>
        /// 任務(wù)列表
        /// </summary>
        private List<Task> TaskList = null;
        /// <summary>
        /// 是否在執(zhí)行任務(wù)中
        /// </summary>
        private bool isPerformTask = false;
        /// <summary>
        /// 執(zhí)行完任務(wù)的回調(diào)
        /// </summary>
        public Action CallBack = null;
 
 
        private static TaskQueue _instance = null;
        public static TaskQueue Instance
        {
            get
            {
                if (_instance == null)
                    _instance = new TaskQueue();
                return _instance;
            }
        }
 
        /// <summary>
        /// 添加任務(wù)
        /// </summary>
        /// <param name="task"></param>
        public void AddTask(Task task)
        {
            if (isPerformTask)
            {
                Console.WriteLine("[TaskQueue]任務(wù)正在執(zhí)行中,此時(shí)不能做賦值操作");
                return;
            }
 
            if (task != null)
            {
                TaskList.Add(task);
            }
        }
 
        /// <summary>
        /// 執(zhí)行任務(wù)
        /// </summary>
        public void PerformTask()
        {
            if (isPerformTask)
            {
                Console.WriteLine("[TaskQueue]任務(wù)正在執(zhí)行中,不可重復(fù)調(diào)用");
                return;
            }
            if (TaskList == null || TaskList.Count == 0)
            {
                Console.WriteLine("[TaskQueue]任務(wù)列表為空");
                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>();
        }
    }
}

調(diào)用:

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("所有任務(wù)執(zhí)行完成");
};
TaskQueue.Instance.AddTask(task1);
TaskQueue.Instance.AddTask(task2);
TaskQueue.Instance.AddTask(task3);
TaskQueue.Instance.CallBack = callback;
TaskQueue.Instance.PerformTask();

運(yùn)行:

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。 

相關(guān)文章

  • C# 使用SharpZipLib生成壓縮包的實(shí)例代碼

    C# 使用SharpZipLib生成壓縮包的實(shí)例代碼

    SharpZipLib是一個(gè)C#的類庫(kù),主要用來(lái)解壓縮Zip,GZip,BZip2,Tar等格式,是以托管程序集的方式實(shí)現(xiàn),可以方便的應(yīng)用于其他的項(xiàng)目之中。本文通過(guò)一個(gè)實(shí)例代碼給大家介紹了C# 使用SharpZipLib生成壓縮包的方法,感興趣的朋友跟隨小編一起看看吧
    2018-09-09
  • C#?代碼大小寫(xiě)規(guī)范說(shuō)明

    C#?代碼大小寫(xiě)規(guī)范說(shuō)明

    這篇文章主要介紹了C#?代碼大小寫(xiě)規(guī)范說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • c#之圓形無(wú)標(biāo)題欄橢圓窗體的實(shí)現(xiàn)詳解

    c#之圓形無(wú)標(biāo)題欄橢圓窗體的實(shí)現(xiàn)詳解

    本篇文章是對(duì)c#中圓形無(wú)標(biāo)題欄橢圓窗體的實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-06-06
  • C#中事件的定義和使用

    C#中事件的定義和使用

    在使用事件時(shí),通常要定義兩個(gè)方法,一個(gè)是和事件定義的委托簽名一致的方法。下面讓我們看看使用事件的具體步驟。
    2016-06-06
  • C#遞歸算法尋找數(shù)組中第K大的數(shù)

    C#遞歸算法尋找數(shù)組中第K大的數(shù)

    首先將向量V從中間位置分開(kāi),分成左和右,分好后,中間值的索引如果恰恰等于K,就找到了,否則如果中間元素索引大于K,則在左子表中繼續(xù)查找,忽略右子表,如果中間值索引小于K,則在右子表中繼續(xù)查找,如此循環(huán)往復(fù)。
    2016-06-06
  • c#中的常用ToString()方法總結(jié)

    c#中的常用ToString()方法總結(jié)

    很多類都重寫(xiě)了ToString方法, 導(dǎo)致很多類的tostring到底執(zhí)行了什么,有哪些參數(shù),都不清楚
    2012-10-10
  • c# BackgroundWorker使用方法

    c# BackgroundWorker使用方法

    這篇文章主要介紹了c# BackgroundWorker使用方法,文中代碼非常詳細(xì),幫助大家更好的參考學(xué)習(xí),感興趣的朋友可以了解下
    2020-06-06
  • C#讀取Excel并轉(zhuǎn)化成XML的方法

    C#讀取Excel并轉(zhuǎn)化成XML的方法

    這篇文章主要介紹了C#讀取Excel并轉(zhuǎn)化成XML的方法,實(shí)例分析了C#操作Excel及XML文件的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-04-04
  • c#刪除指定文件夾中今天之前的文件

    c#刪除指定文件夾中今天之前的文件

    本文主要介紹了c#刪除指定文件夾中今天之前文件的方法,具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-02-02
  • C#遍歷文件夾及其子目錄的完整實(shí)現(xiàn)方法

    C#遍歷文件夾及其子目錄的完整實(shí)現(xiàn)方法

    這篇文章主要介紹了C#遍歷文件夾及其子目錄的方法,涉及C#文件與目錄的基本操作技巧,簡(jiǎn)單實(shí)用,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2016-06-06

最新評(píng)論