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

C#多線程基本使用小結(jié)

 更新時(shí)間:2024年10月16日 15:00:07   作者:小威編程  
C#多線程編程涉及Thread、Task、異步和Parallel等工具,Thread類用于創(chuàng)建獨(dú)立線程,通過(guò)Priority屬性設(shè)置優(yōu)先級(jí),而線程池管理線程的調(diào)度和重用,本文給大家介紹C#多線程基本使用小結(jié),感興趣的朋友跟隨小編一起看看吧

線程是并發(fā)編程的基礎(chǔ)概念之一。在現(xiàn)代應(yīng)用程序中,我們通常需要執(zhí)行多個(gè)任務(wù)并行處理,以提高性能。C# 提供了多種并發(fā)編程工具,如Thread、Task、異步編程和Parallel等。

Thread 類

Thread 類是最基本的線程實(shí)現(xiàn)方法。使用Thread類,我們可以創(chuàng)建并管理獨(dú)立的線程來(lái)執(zhí)行任務(wù)。

基本使用Thread 

創(chuàng)建一個(gè)新的實(shí)例對(duì)象,將一個(gè)方法直接給Thread類,并使用實(shí)例對(duì)象啟動(dòng)線程運(yùn)行。

   static void Test() {
         Console.WriteLine("Test事件開始執(zhí)行");
            Thread.Sleep(1000);
            Console.WriteLine("Test事件睡眠之后打印數(shù)據(jù)");
            Console.WriteLine("Test事件id: " + Thread.CurrentThread.ManagedThreadId);
        }
        static void Main(string[] args)
        {
            #region //主線程id
            Console.WriteLine("主線程id: " + Thread.CurrentThread.ManagedThreadId);
            #endregion
            #region //傳遞一個(gè)方法給線程,執(zhí)行方法
            Thread t = new Thread(Test);
            t.Start();
            #endregion
}

線程數(shù)據(jù)傳輸

傳遞單個(gè)參數(shù)

Thread 提供了一個(gè) Start(object parameter) 方法,可以在啟動(dòng)線程時(shí)傳遞一個(gè)參數(shù)。

 
        static int Downlod(object obj) {
            string str = obj as string;
            Console.WriteLine(str);
        }
     static void Main(string[] args)
        {
      Thread t1 = new Thread(Downlod);
           //這里傳遞的參數(shù)是字符串
            t1.Start("數(shù)據(jù)傳遞方法執(zhí)行 ,數(shù)據(jù)傳遞方法id: "+Thread.CurrentThread.ManagedThreadId);
}

這種方式適用于需要傳遞單個(gè)參數(shù)的情況。

使用類的實(shí)例方法傳遞多個(gè)參數(shù)

先new一個(gè)類的實(shí)例,給實(shí)例字段賦值,調(diào)用類的實(shí)例,通過(guò)實(shí)例調(diào)用方法,構(gòu)造函數(shù)接收參數(shù),然后在線程中調(diào)用該實(shí)例的方法。

     static void Main(string[] args)
        {
// 使用 DownloadTool 實(shí)例化并傳遞數(shù)據(jù)
DownloadTool downloadTool = new DownloadTool("www.baidu.com", "這是下載鏈接哦");
Thread thread = new Thread(downloadTool.Download);
thread.Start();
}
public class DownloadTool
{
    private string url;
    private string message;
    public DownloadTool(string url, string message)
    {
        this.url = url;
        this.message = message;
    }
    public void Download()
    {
        Console.WriteLine("下載鏈接: " + url);
        Console.WriteLine("提示信息: " + message);
        Console.WriteLine("Download 線程 ID: " + Thread.CurrentThread.ManagedThreadId);
    }
}
 

當(dāng) thread 線程啟動(dòng)時(shí),它會(huì)執(zhí)行 downloadTool.Download() 方法,輸出傳遞的數(shù)據(jù)。

線程優(yōu)先級(jí) 

在 C# 中,可以使用 Thread.Priority 屬性來(lái)設(shè)置線程的優(yōu)先級(jí)。線程優(yōu)先級(jí)決定了操作系統(tǒng)在多線程環(huán)境中調(diào)度線程的順序,但并不保證高優(yōu)先級(jí)的線程總是比低優(yōu)先級(jí)的線程更早或更頻繁地執(zhí)行。

線程優(yōu)先級(jí)級(jí)別

C# 提供了五個(gè)線程優(yōu)先級(jí)級(jí)別,定義在 ThreadPriority 枚舉中:

  • Lowest:最低優(yōu)先級(jí)。操作系統(tǒng)盡可能少地調(diào)度這個(gè)優(yōu)先級(jí)的線程。
  • BelowNormal:低于正常的優(yōu)先級(jí)。優(yōu)先級(jí)比 Normal 低,但高于 Lowest。
  • Normal:默認(rèn)優(yōu)先級(jí),大多數(shù)線程默認(rèn)的優(yōu)先級(jí)。適用于一般用途。
  • AboveNormal:高于正常的優(yōu)先級(jí)。操作系統(tǒng)更傾向于調(diào)度這個(gè)優(yōu)先級(jí)的線程。
  • Highest:最高優(yōu)先級(jí)。操作系統(tǒng)盡可能多地調(diào)度這個(gè)優(yōu)先級(jí)的線程。
  internal class Program
    {
        static void A()
        {
            int i = 0;
            while (true)
            {
                i++;
                Console.WriteLine($"A 輸出第{i}");
                Thread.Sleep(1000);
            }
        }
        static void B()
        {
            int i = 0;
            while (true)
            {
                i++;
                Console.WriteLine($"B 輸出第{i}");
                Thread.Sleep(1000);
            }
        }
        static void Main(string[] args)
        {
            //在C#中,線程的優(yōu)先級(jí)可以通過(guò)Thread.Priority屬性來(lái)設(shè)置和獲取。
//        Lowest: 線程的優(yōu)先級(jí)是最低的。在系統(tǒng)中存在其他活動(dòng)線程時(shí),此優(yōu)先級(jí)的線程很少得到執(zhí)行。
//BelowNormal: 線程的優(yōu)先級(jí)低于正常線程。
//Normal: 線程的優(yōu)先級(jí)是普通的,這是線程的默認(rèn)優(yōu)先級(jí)。
//AboveNormal: 線程的優(yōu)先級(jí)高于正常線程。
//Highest: 線程的優(yōu)先級(jí)是最高的。此優(yōu)先級(jí)的線程會(huì)盡量?jī)?yōu)先于其他所有優(yōu)先級(jí)的線程執(zhí)行。
            Thread a = new Thread(A);
            Thread b = new Thread(B);
            a.Priority = ThreadPriority.Highest;
            a.Start();
            b.Priority = ThreadPriority.Lowest;
            b.Start();
            Console.WriteLine("按任意鍵停止線程...");
            Console.ReadKey();
            a.Join();
            b.Join();
            Console.WriteLine("線程已停止");
        }
    }
  • A 被設(shè)置為最高優(yōu)先級(jí) ThreadPriority.Highest
  • B 被設(shè)置為最低優(yōu)先級(jí) ThreadPriority.Lowest。

注意事項(xiàng)

  • 優(yōu)先級(jí)不是絕對(duì)控制:操作系統(tǒng)可能會(huì)忽略優(yōu)先級(jí)設(shè)置,特別是在資源有限的系統(tǒng)中。高優(yōu)先級(jí)線程不一定會(huì)一直執(zhí)行,也不能阻止低優(yōu)先級(jí)線程的執(zhí)行。
  • 使用優(yōu)先級(jí)的適用場(chǎng)景:設(shè)置線程優(yōu)先級(jí)可能適用于實(shí)時(shí)系統(tǒng)(例如,某些任務(wù)需要優(yōu)先處理)。但是,大多數(shù)應(yīng)用程序通??梢允褂媚J(rèn)的 Normal 優(yōu)先級(jí)。
  • 避免使用過(guò)多的高優(yōu)先級(jí)線程:如果所有線程都被設(shè)置為 Highest,系統(tǒng)的整體性能可能會(huì)下降,甚至導(dǎo)致線程爭(zhēng)用 CPU 資源的情況。
  • CPU 密集型任務(wù):在 CPU 密集型任務(wù)中,優(yōu)先級(jí)可能會(huì)對(duì)性能產(chǎn)生較大影響,因?yàn)閮?yōu)先級(jí)高的線程可能會(huì)占用更多的 CPU 時(shí)間。

線程優(yōu)先級(jí)的最佳實(shí)踐

  • 默認(rèn)使用 Normal 優(yōu)先級(jí),除非有特殊原因。
  • 避免濫用 Highest 優(yōu)先級(jí),因?yàn)樗鼤?huì)對(duì)系統(tǒng)資源產(chǎn)生影響。
  • 在 I/O 密集型的線程中,優(yōu)先級(jí)通常不會(huì)有顯著差異,因?yàn)檫@些線程在等待 I/O 操作完成時(shí),CPU 會(huì)調(diào)度其他線程。

通過(guò)合理設(shè)置線程優(yōu)先級(jí),可以幫助操作系統(tǒng)更好地調(diào)度線程,以滿足應(yīng)用程序的需求。 但通常在 .NET 應(yīng)用程序中,多數(shù)情況下使用默認(rèn)的 Normal 優(yōu)先級(jí)就足夠了。

線程池

線程池 (ThreadPool) 是一種高效的管理和調(diào)度線程的方式。線程池自動(dòng)管理線程的創(chuàng)建、重用和銷毀,從而減少了手動(dòng)創(chuàng)建和管理線程的開銷。

為什么使用線程池

  • 性能更高:線程池會(huì)重用現(xiàn)有的線程,減少了創(chuàng)建和銷毀線程的開銷。
  • 自動(dòng)管理:線程池會(huì)根據(jù)系統(tǒng)負(fù)載動(dòng)態(tài)調(diào)整線程數(shù)量。
  • 避免線程資源不足:線程池限制了同時(shí)運(yùn)行的線程數(shù),避免了線程過(guò)多導(dǎo)致的資源耗盡問(wèn)題。

基本使用 ThreadPool.QueueUserWorkItem 方法將任務(wù)排入線程池隊(duì)列。

using System;
using System.Threading;
class Program
{
    static void Main(string[] args)
    {
        // 將任務(wù)排入線程池
        ThreadPool.QueueUserWorkItem(DoWork, "任務(wù) 1");
        ThreadPool.QueueUserWorkItem(DoWork, "任務(wù) 2");
        Console.WriteLine("主線程完成");
        Thread.Sleep(3000); // 等待線程池中的任務(wù)完成
    }
    static void DoWork(object state)
    {
        string taskName = (string)state;
        Console.WriteLine($"{taskName} 開始執(zhí)行 - 線程ID: {Thread.CurrentThread.ManagedThreadId}");
        Thread.Sleep(1000); // 模擬耗時(shí)操作
        Console.WriteLine($"{taskName} 執(zhí)行完成 - 線程ID: {Thread.CurrentThread.ManagedThreadId}");
    }
}

運(yùn)行結(jié)果QueueUserWorkItem自動(dòng)分配線程來(lái)執(zhí)行任務(wù)。

QueueUserWorkItem 方法將任務(wù)排入線程池。它接收一個(gè)委托(即方法)和一個(gè)可選的狀態(tài)對(duì)象(傳遞給方法的數(shù)據(jù))。

DoWork 方法接受一個(gè)參數(shù) state,這是從 QueueUserWorkItem 傳遞的。

Thread.Sleep(3000) 確保主線程不會(huì)立即退出,使得線程池中的任務(wù)有機(jī)會(huì)完成。

使用帶返回值的線程池任務(wù)

C# 中的 ThreadPool 通常不直接支持返回值。如果需要獲得任務(wù)結(jié)果,可以使用 Task,因?yàn)?Task 本質(zhì)上也是線程池的一部分。Task 更適合于帶返回值的異步操作。這里使用 Task.Run 來(lái)代替 ThreadPool

     static void Main(string[] args)
        {
  //使用tesk多線程
           int a= Task.Run(() =>
            {
              int a =  Dowload();
                return a;
            }).Result;
            Task<int> task = Task<int>.Run(()=>{
             int a =   Dowload();
                return a;
            });
            //初始化一個(gè)CancellationTokenSource實(shí)例
            CancellationTokenSource source = new CancellationTokenSource();
            //task.Start();
            task.Wait(1000);
            source.Cancel();
        int result  =    task.Result;
            Console.WriteLine(result);
            Console.WriteLine($"tesk返回值{a}");
}
        static int  Dowload() {
            int a = 0;
            for (int i = 0; i < 10; i++)
            {
              a=  a + i + 1;
            }
         int?  id= Task.CurrentId;
            Console.WriteLine("Current thread ID: " + id);
            return a;
        }

線程池的限制

  • 任務(wù)運(yùn)行時(shí)間過(guò)長(zhǎng):線程池中的線程本質(zhì)上是共享資源,如果某個(gè)任務(wù)運(yùn)行時(shí)間太長(zhǎng),將會(huì)占用線程池中的線程,導(dǎo)致其他任務(wù)無(wú)法及時(shí)執(zhí)行。
  • 不適合實(shí)時(shí)系統(tǒng):線程池中的任務(wù)調(diào)度是由系統(tǒng)管理的,無(wú)法保證精確的實(shí)時(shí)性。
  • 有限的線程數(shù)量:在高并發(fā)場(chǎng)景中,如果線程池中的線程全部被占用,新的任務(wù)將會(huì)等待,直到有線程可用。

線程池總結(jié)

線程池是一種高效的并發(fā)處理方式,適合于大多數(shù)輕量級(jí)的后臺(tái)任務(wù)。在現(xiàn)代 C# 編程中,建議使用 Taskasync/await 進(jìn)行異步操作,因?yàn)樗鼈兡芎?jiǎn)化代碼,并且使用底層的線程池來(lái)管理線程。如果需要精確控制線程的執(zhí)行,通常建議使用手動(dòng)管理的 Thread 等。 

線程鎖

使用多線程,在多線程編程中,如果多個(gè)線程同時(shí)訪問(wèn)和修改共享資源(如全局變量、文件、數(shù)據(jù)庫(kù)等),可能會(huì)導(dǎo)致數(shù)據(jù)不一致或競(jìng)爭(zhēng)條件。為了避免這種情況,多線程鎖通過(guò)控制對(duì)共享資源的訪問(wèn)來(lái)保證線程安全性。

資源沖突示例:

  static void Main(string[] args)
        {
             //調(diào)用方法循環(huán)創(chuàng)建新的線程來(lái)執(zhí)行方法
            StateObject state = new StateObject();
            for (int i = 0; i < 30; i++)
            {
                Thread thread = new Thread(state.ChangState);
                thread.Start();
            }
            Console.ReadKey();
        }
//一個(gè)StateObject類
        public class StateObject
        {
            private int state = 5;
//里面有個(gè)狀態(tài)改變方法,當(dāng)狀態(tài)等于5的時(shí)候進(jìn)入到方法中,然后state+1 打印的應(yīng)該是6 和線程id
            public void ChangState()
            {
                if (state == 5)
                {
                    state++;
                    Console.WriteLine($"state:{state}  線程id:" + Thread.CurrentThread.ManagedThreadId);
                }
                state = 5;
            }
        }

 運(yùn)行結(jié)果:

因?yàn)橘Y源沖突的原因,有一些線程執(zhí)行的時(shí)候,可能另外一個(gè)線程沒(méi)有執(zhí)行完,另外一個(gè)線程就已經(jīng)進(jìn)入到方法里面了。因?yàn)橛行薷牡牟僮鲗?dǎo)致State狀態(tài)混亂,資源沖突。這時(shí)候我們就需要一個(gè)東西來(lái)維護(hù),讓線程執(zhí)行指定方法時(shí)一個(gè)一個(gè)的執(zhí)行,不會(huì)沖突。

簡(jiǎn)單使用lock鎖

1.創(chuàng)建一個(gè)private readonly object lockObject = new object(); // 鎖對(duì)象

2.使用lock (lockObject){

//業(yè)務(wù)代碼,執(zhí)行到有修改的操作的代碼

} // 使用鎖對(duì)象來(lái)確保線程安全

        static void Main(string[] args)
        {
            StateObject state = new StateObject();
            for (int i = 0; i < 100; i++)
            {
                Thread thread = new Thread(state.ChangState);
                thread.Start();
            }
            Console.ReadKey();
        }
        public class StateObject
        {
            private object _lock = new object();
            private int state = 5;
            public void ChangState()
            {
                //使用鎖保證每次執(zhí)行方法的都是一個(gè)線程,防止資源沖突
                lock (_lock)
                {
                    if (state == 5)
                    {
                        state++;
                        Console.WriteLine($"state:{state}  線程id:" + Thread.CurrentThread.ManagedThreadId);
                    }
                    state = 5;
                }
            }
        }

 這樣運(yùn)行起來(lái)就能把每個(gè)線程操作隔離開,保證state的狀態(tài)不會(huì)沖突。

為什么要?jiǎng)?chuàng)建一個(gè) object 對(duì)象作為鎖?

  • 專用性:創(chuàng)建一個(gè)專用的鎖對(duì)象(如 private readonly object lockObject = new object();),可以確保鎖定的是特定的同步邏輯,而不是其他對(duì)象。這有助于避免意外的鎖沖突或死鎖。
  • 避免使用其他共享對(duì)象:雖然可以使用任意的引用類型對(duì)象作為鎖對(duì)象(包括 thisType 對(duì)象),但這可能會(huì)帶來(lái)不必要的風(fēng)險(xiǎn),尤其是在 public 方法或?qū)ο笾校@樣可能會(huì)導(dǎo)致意外的鎖定沖突。

常見問(wèn)題死鎖:

鎖并不是萬(wàn)能,也不是有鎖就是最好,要看情況使用,鎖也會(huì)產(chǎn)生問(wèn)題,常見的問(wèn)題就是死鎖等問(wèn)題。

演示死鎖:

thread1方法1 的鎖里面嵌套鎖住了thread2的鎖,thread2方法2的鎖里面嵌套鎖住了thread1的鎖,這種鎖與鎖嵌套使用,就是容易出問(wèn)題。導(dǎo)致線程鎖死程序無(wú)法動(dòng)彈。

   static void Main(string[] args)
        {
            DeadlockExample deadlockExample = new DeadlockExample();
            Thread t1 = new Thread(deadlockExample.Thread1);
            Thread t2 = new Thread(deadlockExample.Thread2);
            t1.Start();
            t2.Start();
            t1.Join();
            t2.Join();
            Console.ReadKey();
        }
    }
   public  class DeadlockExample
    {
        private static object lock1 = new object();
        private static object lock2 = new object();
        public  void Thread1()
        {
            lock (lock1)
            {
                Console.WriteLine("線程1:已獲取鎖1,正在等待鎖2。。。");
                Thread.Sleep(100);  // 模擬某些工作
                lock (lock2)
                {
                    Console.WriteLine("線程1:獲得鎖2");
                }
            }
        }
        public  void Thread2()
        {
            lock (lock2)
            {
                Console.WriteLine("線程2:已獲取鎖2,正在等待鎖1。。。");
                Thread.Sleep(100);  // 模擬某些工作
                lock (lock1)
                {
                    Console.WriteLine("線程2:獲得鎖1");
                }
            }
        }
    }

運(yùn)行結(jié)果:

死鎖發(fā)生在兩個(gè)或多個(gè)線程相互等待對(duì)方持有的資源,導(dǎo)致所有線程都無(wú)法繼續(xù)執(zhí)行。

總結(jié):

多線程鎖在 C# 中主要用于解決以下問(wèn)題:

  • 競(jìng)態(tài)條件:通過(guò)鎖機(jī)制防止多個(gè)線程同時(shí)訪問(wèn)和修改共享資源,確保數(shù)據(jù)一致性。
  • 死鎖:防止多個(gè)線程相互等待資源,通過(guò)鎖的順序或者避免嵌套鎖來(lái)解決。
  • 資源饑餓:確保每個(gè)線程都能獲取資源,使用 Monitor.TryEnter 等機(jī)制防止無(wú)限等待。
  • 讀寫鎖:允許多個(gè)線程并發(fā)讀取資源,但寫入時(shí)互斥,適合讀多寫少的場(chǎng)景。

C# 提供了多種鎖機(jī)制,開發(fā)者可以根據(jù)應(yīng)用場(chǎng)景選擇合適的鎖類型。

如果不想使用 lock 關(guān)鍵字,C# 還提供了其他鎖機(jī)制,比如 Mutex、SemaphoreMonitor

到此這篇關(guān)于C#多線程基本使用和探討的文章就介紹到這了,更多相關(guān)C#多線程使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C#圖表算法之無(wú)向圖

    C#圖表算法之無(wú)向圖

    這篇文章介紹了C#圖表算法之無(wú)向圖,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-04-04
  • 用序列化實(shí)現(xiàn)List<T> 實(shí)例的深復(fù)制(推薦)

    用序列化實(shí)現(xiàn)List<T> 實(shí)例的深復(fù)制(推薦)

    下面小編就為大家?guī)?lái)一篇用序列化實(shí)現(xiàn)List<T> 實(shí)例的深復(fù)制(推薦)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-02-02
  • c#中利用委托反射將DataTable轉(zhuǎn)換為實(shí)體集的代碼

    c#中利用委托反射將DataTable轉(zhuǎn)換為實(shí)體集的代碼

    c#中利用委托反射將DataTable轉(zhuǎn)換為實(shí)體集的代碼,需要的朋友可以參考下
    2012-10-10
  • c#的datatable轉(zhuǎn)list示例

    c#的datatable轉(zhuǎn)list示例

    這篇文章主要介紹了c#的datatable轉(zhuǎn)list示例,代碼中有注釋,需要的朋友可以參考下
    2014-04-04
  • 不用IDE寫C#的Hello World的方法

    不用IDE寫C#的Hello World的方法

    這篇文章主要介紹了不用IDE寫C#的Hello World的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2015-10-10
  • 使用C#在注冊(cè)表中保存信息的例子

    使用C#在注冊(cè)表中保存信息的例子

    最近做的項(xiàng)目需要在注冊(cè)表中記錄一些用戶設(shè)置,方便在程序下次啟動(dòng)時(shí)讀取設(shè)置,應(yīng)用上次用戶保存的設(shè)置,挺簡(jiǎn)單的
    2014-04-04
  • WPF實(shí)現(xiàn)列表分頁(yè)控件的示例代碼

    WPF實(shí)現(xiàn)列表分頁(yè)控件的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何利用WPF實(shí)現(xiàn)列表分頁(yè)控件,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)或工作有一定幫助,感興趣的小伙伴可以了解一下
    2022-10-10
  • 深入理解C#中常見的委托

    深入理解C#中常見的委托

    本篇文章是對(duì)C#中常見的委托進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-06-06
  • 淺析C#中結(jié)構(gòu)與類的區(qū)別

    淺析C#中結(jié)構(gòu)與類的區(qū)別

    本文主要對(duì)C#結(jié)構(gòu)與類的區(qū)別進(jìn)行簡(jiǎn)要分析,文中舉了實(shí)例,便于理解,具有很好的參考價(jià)值,需要的朋友一起來(lái)看下吧
    2016-12-12
  • Unity搖桿制作的方法

    Unity搖桿制作的方法

    這篇文章主要為大家詳細(xì)介紹了Unity搖桿制作的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08

最新評(píng)論