【C#进阶】多线程和异步编程_2024-06-22

关于多线程和异步编程简单来说,就是多线程并行执行任务提速,异步编程等待不浪费资源,并发集合确保数据访问安全,三者合力提升程序效率与反应能力。

1. 理解线程

想象一下,你在厨房做饭,同时需要洗菜、切菜、炒菜。如果你一个人来做,就需要在这些任务之间来回切换,这很慢。但如果请几个朋友帮忙,每人负责一项任务,大家同时工作,效率就高多了。这里的“朋友”就像是计算机中的“线程”。

线程就是计算机程序中执行任务的最小单位。一个程序默认启动时只有一个主线程,但可以通过创建额外的线程来同时执行多个任务,这就是多线程

示例代码:

using System;
using System.Threading;

class MultiThreadingDemo
{
    static void Main()
    {
        // 这是主线程
        Console.WriteLine("主线程开始");
        
        // 创建并启动一个新的线程
        Thread thread = new Thread(DoWork);
        thread.Start();
        
        Console.WriteLine("主线程继续做其他事情");
        
        // 等待新线程完成(非必须,这里为了演示)
        thread.Join();
        
        Console.WriteLine("所有任务完成,主线程结束");
    }
    
    static void DoWork()
    {
        Console.WriteLine("新线程开始执行任务");
        Thread.Sleep(2000); // 模拟耗时操作
        Console.WriteLine("新线程任务完成");
    }
}

注释说明:这段代码中,Main方法所在的线程是主线程,它创建了一个新线程DoWork去执行一个耗时任务。Thread.Sleep(2000)模拟了这个耗时操作,让新线程暂停2秒,期间主线程可以继续执行其他任务。

2. Task和异步编程模型(async和await)

有时候,我们不希望直接管理线程,而是希望程序自动为我们处理并发问题。这时候,就可以使用.NET提供的Taskasync/await关键字。

想象你在等待外卖,你可以选择一直站在门口等(阻塞),也可以继续做其他事,听到门铃响再去拿(异步)。async/await就是让你的程序在等待某些耗时操作(如网络请求)时,可以去做别的事,不浪费时间。

示例代码:

using System;
using System.Threading.Tasks;

class AsyncDemo
{
    static async Task Main()
    {
        Console.WriteLine("开始下载文件");
        
        // 异步下载文件,不会阻塞主线程
        await DownloadFileAsync();
        
        Console.WriteLine("文件下载完成");
    }
    
    static async Task DownloadFileAsync()
    {
        // 模拟文件下载耗时操作
        await Task.Delay(2000);
        Console.WriteLine("文件下载中...");
    }
}

注释说明DownloadFileAsync方法模拟了文件下载,使用Task.Delay(2000)模拟耗时操作。await关键字让调用它的方法(这里是Main方法)在等待时可以“放手”,去做其他事情,直到DownloadFileAsync完成才继续往下执行。

3. 并发集合和线程安全

当你在多线程环境下访问和修改共享数据时,可能会遇到数据不一致的问题,这叫做“竞态条件”。为了解决这个问题,.NET提供了线程安全的集合,比如ConcurrentDictionary

想象你和朋友同时编辑一份购物清单,如果不小心同时添加了同样的物品,就会出错。线程安全的集合就像每个人都有自己的笔,在写之前先确认没人同时写,保证清单的正确性。

示例代码:

using System.Collections.Concurrent;
using System.Threading.Tasks;

class ThreadSafeCollectionsDemo
{
    static ConcurrentDictionary<string, int> shoppingList = new ConcurrentDictionary<string, int>();

    static async Task AddItemAsync(string item)
    {
        // 尝试添加或更新数量,线程安全
        shoppingList.AddOrUpdate(item, 1, (key, oldValue) => oldValue + 1);
        await Task.Yield(); // 模拟一点点耗时,让并发效果更明显
    }

    static async Task Main()
    {
        var tasks = new Task[10];
        
        for (int i = 0; i < 10; i++)
        {
            tasks[i] = AddItemAsync("苹果");
        }
        
        await Task.WhenAll(tasks);
        
        foreach (var item in shoppingList)
        {
            Console.WriteLine($"{item.Key}: {item.Value}");
        }
    }
}

注释说明:这段代码展示了如何使用ConcurrentDictionary来安全地在多线程环境下添加购物清单项。即使多个线程同时尝试添加“苹果”,AddOrUpdate方法也会确保不会有重复计数的问题。

总结:

  1. 多线程入门:线程是程序执行任务的基本单位,多线程允许程序同时执行多个任务,如同厨房里多位厨师同时准备不同菜肴,显著提升工作效率。通过创建和管理线程,你能使程序运行更加流畅,响应更快。

  2. 异步编程与Taskasyncawait关键字是C#中异步编程的核心,它们使程序能在等待耗时操作(如网络请求、磁盘I/O)时释放当前线程去做其他工作,如同等待外卖时可以继续做家务,不白白浪费时间,从而优化程序的整体性能。

  3. 并发集合与线程安全:在多线程环境中,直接访问共享数据可能导致数据不一致性问题。ConcurrentDictionary等并发集合为此而生,它们内置同步机制,确保了多线程访问时的数据安全,有效避免了竞态条件,让数据操作既高效又可靠。

这些知识点相互支撑,构成了处理并发问题、提升程序效率与稳定性的坚实基础。掌握它们,你就能在编写高质量、高性能应用程序的道路上迈出重要一步。

posted @ 2024-06-22 22:10  StarYou  阅读(120)  评论(0编辑  收藏  举报