C# 多线程编程
                           
天天向上
发布: 2025-04-20 19:23:16

原创
713 人浏览过

在 C# 中,多线程编程是并行和并发处理任务的重要方式,它允许程序在多个线程中同时执行代码。通过利用多核处理器的优势,多线程可以显著提高程序的性能,尤其是在处理耗时操作时(如网络请求、文件操作、大数据处理等)。


1. 多线程基础

C# 中的多线程通常是通过 System.Threading 命名空间提供的类来管理的。最常用的方式是使用 Thread 类来创建和管理线程。每个线程都有一个独立的执行流,操作系统调度线程的执行。

示例:创建一个简单的线程

using System;
using System.Threading;

class Program
{
    static void Main()
    {
        // 创建并启动线程
        Thread thread = new Thread(DoWork);
        thread.Start();

        // 主线程继续执行
        Console.WriteLine("主线程继续执行...");
    }

    static void DoWork()
    {
        // 模拟一些工作
        Thread.Sleep(1000);
        Console.WriteLine("工作线程执行完毕");
    }
}

在上面的例子中,Thread 类用于创建一个新线程,并让其执行 DoWork 方法。


2. 线程池(ThreadPool)

为了避免频繁地创建和销毁线程,可以使用线程池。线程池会复用线程,从而提高程序的性能和响应速度。C# 提供了 ThreadPool 类来管理线程池。

示例:使用线程池

using System;
using System.Threading;

class Program
{
    static void Main()
    {
        // 使用线程池来执行任务
        ThreadPool.QueueUserWorkItem(DoWork);

        // 主线程继续执行
        Console.WriteLine("主线程继续执行...");
    }

    static void DoWork(object state)
    {
        // 模拟一些工作
        Thread.Sleep(1000);
        Console.WriteLine("工作线程执行完毕");
    }
}

线程池会自动管理线程的生命周期,减少了创建线程的开销。


3. Task 类(异步编程)

Task 类是 C# 中用于管理异步操作和并行编程的高级抽象。它提供了一种更简便的方式来管理多线程任务,并且与 asyncawait 关键字结合使用,可以更轻松地进行异步编程。

示例:使用 Task 类

using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        // 创建并启动任务
        Task task = Task.Run(() => DoWork());

        // 等待任务完成
        await task;

        Console.WriteLine("任务执行完毕");
    }

    static void DoWork()
    {
        // 模拟一些工作
        Task.Delay(1000).Wait();
        Console.WriteLine("工作线程执行完毕");
    }
}

在这个例子中,Task.Run 用于启动一个任务,await 等待任务完成。Task 更适合用于处理异步操作或并行计算。


4. 并行编程(Parallel)

C# 还提供了 Parallel 类,旨在简化并行编程。它能够并行地处理一个循环中的多个迭代,自动分配多个线程来加速任务。

示例:使用 Parallel.For 进行并行计算

using System;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        // 使用 Parallel.For 来并行处理循环
        Parallel.For(0, 10, i =>
        {
            Console.WriteLine($"正在处理: {i} 在线程 {Task.CurrentId}");
        });

        Console.WriteLine("并行任务执行完毕");
    }
}

Parallel.For 会并行执行指定区间内的循环,自动将每个迭代分配到不同的线程,从而加快执行速度。


5. 线程同步与锁(Locks)

在多线程环境中,如果多个线程同时访问共享资源,可能会导致数据竞争(race condition)和不一致的状态。为了避免这种情况,可以使用来确保线程同步。

示例:使用 lock 锁定共享资源

using System;
using System.Threading;

class Program
{
    static int counter = 0;
    static readonly object lockObj = new object();  // 锁对象

    static void Main()
    {
        Thread t1 = new Thread(IncrementCounter);
        Thread t2 = new Thread(IncrementCounter);

        t1.Start();
        t2.Start();

        t1.Join();
        t2.Join();

        Console.WriteLine("最终计数器值: " + counter);
    }

    static void IncrementCounter()
    {
        for (int i = 0; i < 1000; i++)
        {
            lock (lockObj)  // 锁定共享资源
            {
                counter++;
            }
        }
    }
}

在这个例子中,lock 关键字确保了同一时刻只有一个线程能够访问 counter 变量,避免了数据竞争。


6. 线程间通信(线程同步)

线程间的通信通常使用事件信号量条件变量等方式来同步多个线程的工作。

示例:使用 ManualResetEvent 进行线程同步

using System;
using System.Threading;

class Program
{
    static ManualResetEvent manualResetEvent = new ManualResetEvent(false);

    static void Main()
    {
        Thread t1 = new Thread(Worker);
        Thread t2 = new Thread(Worker);

        t1.Start();
        t2.Start();

        // 主线程等待信号
        Console.WriteLine("主线程等待工作线程完成...");
        manualResetEvent.WaitOne();
        Console.WriteLine("主线程继续执行...");
    }

    static void Worker()
    {
        Console.WriteLine("工作线程开始执行...");
        Thread.Sleep(2000);  // 模拟工作
        Console.WriteLine("工作线程完成...");
        manualResetEvent.Set();  // 发出信号
    }
}

在这个例子中,ManualResetEvent 用于线程间的信号通信。当工作线程完成时,主线程才能继续执行。


7. 多线程中的异常处理

在多线程编程中,处理线程中的异常尤为重要。如果线程中的异常没有被捕获,整个应用可能会崩溃。可以使用 try-catch 块捕获异常,或者使用 Task 进行异步操作时处理异常。

示例:在任务中捕获异常

using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        try
        {
            await Task.Run(() =>
            {
                throw new InvalidOperationException("任务发生了异常");
            });
        }
        catch (Exception ex)
        {
            Console.WriteLine($"捕获到异常: {ex.Message}");
        }
    }
}

8. 性能优化与多线程

多线程编程虽然能够提高性能,但也有一些常见的性能问题需要注意:

  • 线程创建开销:频繁创建线程会导致性能下降,使用线程池(ThreadPool)或任务(Task)可以避免这个问题。
  • 线程上下文切换:过多线程竞争 CPU 时间会导致频繁的上下文切换,从而影响性能。适当控制线程的数量很重要。
  • 共享资源竞争:如果多个线程频繁访问共享资源,会导致锁竞争。避免过多的锁定,尽可能使用无锁数据结构。

🔗 延伸阅读

发表回复 0

Your email address will not be published. Required fields are marked *