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

C#多線程之任務的用法詳解

 更新時間:2022年04月13日 10:02:02   作者:Ruby_Lu  
本文詳細講解了C#多線程之任務的用法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

Parallel類(http://www.dbjr.com.cn/article/244267.htm)的并行任務需要結(jié)束后才能運行后面的代碼,如果想不等結(jié)束后在開始動作,可以使用Task類更好地控制并行動作。
任務表示應完成的某個工作單元。這個工作單元可以在單獨的線程中運行,也可以以同步方式啟動一個任務,這需要等待主調(diào)線程。使用任務不僅可以獲得一個抽象層,還可以對底層線程進行很多控制。
任務相對Parallel類提供了非常大的靈活性。例如,可以定義連續(xù)的工作——在一個任務完成后該執(zhí)行什么工作。這可以根據(jù)任務成功與否來分。還可以在層次結(jié)構(gòu)中安排任務。例如,父任務可以創(chuàng)建新的子任務。

一.啟動任務

要啟動任務,可以使用TaskFactory類或Task類的構(gòu)造函數(shù)和Start()方法。Task類的構(gòu)造函數(shù)在創(chuàng)建任務上靈活性比較大。
在啟動任務時,會創(chuàng)建Task類的一個實例,利用Action或Action<T>委托(不帶參數(shù)或帶一個參數(shù)),可以指定應運行的代碼。

1.使用線程池的任務

線程池提供了一個后臺線程的池(后面詳細介紹了線程池)。線程池獨自管理線程,根據(jù)需要增加或減少線程池中的線程數(shù)。線程池中的線程用于實現(xiàn)一些動作,之后仍然返回線程池中。
下面介紹創(chuàng)建線程池的任務的四種方法:
先定義一個要調(diào)用使用的方法:

  //避免寫入控制臺的操作交叉,這里使用lock關(guān)鍵字同步
        static object taskMethodLock = new object();
        static void TaskMethod(object title)
        {
            lock (taskMethodLock)
            {
                Console.WriteLine(title);
                Console.WriteLine("task id:{0},thread:{1}",Task.CurrentId,Thread.CurrentThread.ManagedThreadId);
                Console.WriteLine("is pooled thread:{0}",Thread.CurrentThread.IsThreadPoolThread);
                Console.WriteLine("is background thread:{0}",Thread.CurrentThread.IsBackground);
            }
        }

(1).使用實例化的TaskFactory類,把TaskMethod方法和TaskMethod方法的參數(shù)傳遞給StartNew方法:

    var tf = new TaskFactory();
    Task t1 = tf.StartNew(TaskMethod,"using a task factory");

(2).使用Task類的靜態(tài)屬性Factory來訪問TaskFactory,以調(diào)用StartNew()方法。類似第一種,也使用了工廠,但對工廠的控制沒那么全面。

    Task t2 = Task.Factory.StartNew(TaskMethod,"using factory via a task");

(3).使用Task的構(gòu)造函數(shù)。實例化Task對象時任務不會執(zhí)行,只是指定Created狀態(tài)。接著調(diào)用Start()方法,啟動任務。

    Task t3 = new Task(TaskMethod,"using a task constructor and Start");
    t3.Start();

(4).直接調(diào)用Task類的Run()方法啟動任務。Run()方法沒有傳遞帶參數(shù)委托的版本,可以通過傳遞lambda表達式。

   Task t4 = Task.Run(()=> TaskMethod("using Run method"));
  static void Main(string[] args)
        {
            var tf = new TaskFactory();
            Task t1 = tf.StartNew(TaskMethod,"using a task factory");

            Task t2 = Task.Factory.StartNew(TaskMethod,"using factory via a task");

            Task t3 = new Task(TaskMethod,"using a task constructor and Start");
            t3.Start();

            Task t4 = Task.Run(()=> TaskMethod("using Run method"));

            Console.ReadKey();
        }

2.同步任務

任務不一定使用線程池中的線程,也可以使用其它線程。任務也可以同步運行,以相同的線程作為主調(diào)線程。
示例:

      static void RunSyncTask()
            {
                TaskMethod("main thread");
                var t = new Task(TaskMethod,"run sync");
                t.RunSynchronously();
            }

輸出:

上面代碼先在主線程上直接調(diào)用TaskMethod方法,然后在創(chuàng)建的Task上調(diào)用。從輸出看到,主線程是一個前臺線程,沒有任務ID,也不是線程池中的線程。調(diào)用RunSynchronously方法時,會使用相同的線程,會創(chuàng)建一個任務。

3.使用單獨線程的任務

上面將到的任務雖然不是線程池中的線程,但使用的是主線程,不是單獨的,不能實現(xiàn)異步。
如果任務的代碼應該長時間運行,就應該使用TaskCreationOptions.LongRunning告訴任務調(diào)度器創(chuàng)建一個新的單獨線程,而不是線程池中的線程。這個線程可以不由線程池管理。當線程來自線程池時,任務調(diào)度器可以決定等待已經(jīng)運行的任務完成,然后使用這個線程,而不是在線程池中創(chuàng)建一個新線程。對于長時間運行的線程,任務調(diào)度器會立即知道等待它們完成是不明智的做法,會創(chuàng)建一個新的線程。
示例:

static void LongRunTask()
            {
                var t = new Task(TaskMethod,"long running",TaskCreationOptions.LongRunning);
                t.Start();
            }

輸出:

二.任務的結(jié)果————Future

任務結(jié)束時,可以把一些有用的狀態(tài)信息寫入共享對象中。這個共享對象必須是線程安全的。另一個選項是使用返回某個結(jié)果的任務。這種任務也叫future,因為它在將來返回一個結(jié)果。這需要使用Task類的一個泛型版本。使用這個類可以定義任務返回的結(jié)果的類型。
示例:
使用泛型類Task<TResult>,TResult是返回類型。通過構(gòu)造函數(shù),把方法傳遞給Func委托,第二個參數(shù)是委托的參數(shù)。

      static void Main(string[] args)
            {
                var t = new Task<Tuple<int, int>>(TaskWithResult,Tuple.Create<int,int>(8,3));
                t.Start();
                Console.WriteLine(t.Result);
                t.Wait();
                Console.WriteLine("result from task:{0},{1}", t.Result.Item1, t.Result.Item2);

                Console.ReadKey();
            }

由任務來調(diào)用來返回結(jié)果的方法可以聲明為任何類型。

static Tuple<int, int> TaskWithResult(object o)
        {
            Tuple<int, int> div = (Tuple<int, int>)o;
            int result = div.Item1 / div.Item2;
            int reminder = div.Item1 % div.Item2;
            Thread.Sleep(10000);
            return Tuple.Create<int, int>(result,reminder);
        }

這里使用了元組(http://www.dbjr.com.cn/article/244045.htm).

三.連續(xù)的任務

通過任務,可以指定在任務完成后,應接著運行另一個特定任務。例如,一個使用前一個任務的結(jié)果的新任務,如果前一個任務失敗了,這個任務就應執(zhí)行一些清理工作。
任務處理程序(前一個任務)或者不帶參數(shù),或者帶一個對象參數(shù),而連續(xù)處理程序有一個Task類型的參數(shù),這里可以訪問前一個任務的相關(guān)信息。
示例:

//一個任務結(jié)束時,可以啟動多個任務,連續(xù)任務也可以有另一個連續(xù)的任務。
        static void Main(string[] args)
        {
            Task t1 = new Task(DoFirst);
            Task t2 = t1.ContinueWith(DoSecond);
            Task t3 = t1.ContinueWith(DoSecond);
            Task t4= t2.ContinueWith(DoSecond);
            t1.Start();
            Console.ReadKey();

        }


        static void DoFirst()
        {
            Console.WriteLine("do some task:{0}",Task.CurrentId);
            Thread.Sleep(3000);
        }
        static void DoSecond(Task t)
        {
            Console.WriteLine("task {0} finished",t.Id);
            Console.WriteLine("this task id:{0}",Task.CurrentId);

        }

無論前一個任務是如何結(jié)束,前面的連續(xù)任務總是在前一個任務結(jié)束時啟動。使用TaskContinuationOptions枚舉中的值,可以指定,連續(xù)任務只有在任務成功或失敗時啟動。

    Task t5 = t1.ContinueWith(DoSecond,TaskContinuationOptions.OnlyOnFaulted);

四.任務的層次結(jié)構(gòu)

利用任務連續(xù)性,可以在一個任務結(jié)束后啟動另一個任務。任務也可以構(gòu)成一個層次結(jié)構(gòu)。在一個任務中啟動一個新的任務時,就啟動了一個父/子層次結(jié)構(gòu)。取消父任務,也會取消子任務。
創(chuàng)建子任務與創(chuàng)建父任務的代碼相同,唯一區(qū)別就就是子任務從另一個任務內(nèi)部創(chuàng)建。
示例:

static void Main(string[] args)
        {
            Task t = new Task(ParentTask);
            t.Start();
            Console.ReadKey();

        }

        static void ParentTask()
        {
            Console.WriteLine("parent task id:{0}",Task.CurrentId);
            var child = new Task(ChildTask);
            child.Start();
            Console.WriteLine("parent  create child");
        }

        static void ChildTask()
        {
            Console.WriteLine("child task");
            
        }

如果父任務在子任務之前結(jié)束,父任務的狀態(tài)就是WaitingForChildrenToComplete。所有子任務也結(jié)束時,父任務的狀態(tài)就是RanToCompletion.

到此這篇關(guān)于C#多線程之任務的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論