Jupyter AI

6 进阶Tutorial:C# 异步编程中的任务与多线程

📅 发表日期: 2024年8月13日

分类: 🔷C# 高级

👁️阅读: --

在前面的章节中,我们探讨了异步编程的关键词 asyncawait。它们帮助我们方便地编写异步代码,使得应用程序在执行长时间运行的操作时也能保持响应性。今天,我们将深入讨论“任务”以及如何在 C# 中实现“多线程”编程,以进一步提升我们的异步编程能力。

任务(Task)

在 C# 中,Task 是一个表示异步操作的类。使用 Task 可以帮助我们更好地管理并发操作。与传统的线程模型相比,Task 提供了更高层次的抽象,使得并行编程更加简单和易读。

创建和运行任务

我们可以通过 Task.Run 方法来创建和运行任务。以下是一个简单的示例,展示如何创建一个任务并在其中执行一些耗时操作:

using System;
using System.Threading.Tasks;

class Program
{
    static void Main(string[] args)
    {
        // 启动一个任务
        Task task = Task.Run(() => PerformLengthyOperation());
        
        // 等待任务完成
        task.Wait();
        
        Console.WriteLine("操作完成!");
    }

    static void PerformLengthyOperation()
    {
        Console.WriteLine("正在执行耗时操作...");
        // 模拟耗时操作
        Task.Delay(2000).Wait(); // 延迟2秒
    }
}

在这个示例中,PerformLengthyOperation 方法将在新的任务中被调用,而主线程则可以等待该任务完成。当我们运行这段代码时,控制台会在 2 秒后显示“操作完成!”的消息。

扩展任务的功能

Task 类提供了许多有用的方法和属性。例如,我们可以使用 ContinueWith 方法添加一个继续任务:

Task task = Task.Run(() => PerformLengthyOperation())
                .ContinueWith(t => Console.WriteLine("继续执行后续操作..."));

在这个例子中,当 PerformLengthyOperation 完成后,ContinueWith 会被调用,这样我们便可以轻松地链式调用多个任务。

多线程

虽然 Task 提供了易用的抽象,但在某些情况下我们仍然需要使用原始的线程来处理低级别的并发控制。C# 中的线程可以使用 System.Threading 命名空间下的 Thread 类来实现。

创建和使用线程

以下是一个简单的多线程示例:

using System;
using System.Threading;

class Program
{
    static void Main(string[] args)
    {
        Thread thread = new Thread(new ThreadStart(PerformLengthyOperation));
        thread.Start(); // 启动线程

        // 主线程可以执行其他任务
        Console.WriteLine("主线程继续工作...");
        
        // 等待子线程完成
        thread.Join();
        Console.WriteLine("子线程已完成!");
    }

    static void PerformLengthyOperation()
    {
        Console.WriteLine("子线程正在执行耗时操作...");
        Thread.Sleep(2000); // 睡眠2秒以模拟耗时
    }
}

在这个示例中,我们创建了一个新线程,并让它运行 PerformLengthyOperation 方法。主线程可以继续执行其他工作,直到调用 Join 方法等待子线程完成。

线程同步

在多线程编程中,数据共享和状态一致性是非常重要的。我们需要使用适当的机制来保证线程安全,例如:

  • lock 关键字
  • Monitor
  • Mutex
  • Semaphore

以下是使用 lock 来同步对共享资源的访问的示例:

using System;
using System.Threading;

class Program
{
    private static int _counter = 0;
    private static readonly object _lock = new object();

    static void Main(string[] args)
    {
        Thread thread1 = new Thread(IncrementCounter);
        Thread thread2 = new Thread(IncrementCounter);

        thread1.Start();
        thread2.Start();

        thread1.Join();
        thread2.Join();

        Console.WriteLine($"最终计数器值: {_counter}");
    }

    static void IncrementCounter()
    {
        for (int i = 0; i < 1000; i++)
        {
            lock (_lock)
            {
                _counter++;
            }
        }
    }
}

在这个示例中,我们在 IncrementCounter 方法中使用 lock 来确保对 _counter 的访问是线程安全的。两个线程同时调用这个方法,使得 _counter 的值能够正确地被递增而不出现竞争条件。

小结

在本节中,我们探讨了 C# 中的 Task 和多线程编程。Task 为异步编程提供了易用的接口,而多线程则让我们能够进行更底层的并发编程。理解这两者的使用场景和适当的应用方法,将有助于我们编写更高效的 C# 程序。

下一篇将带您进入 LINQLambda 表达式的世界,展示如何使用 LINQ 查询语法对数据进行操作。敬请期待!