C#异步和多线程,Thread,Task和async/await关键字--12

目录

一.多线程和异步的区别

1.多线程

2.异步编程

多线程和异步的区别

二.Thread,Task和async/await关键字的区别

1.Thread

2.Task

3.async/await

三.Thread,Task和async/await关键字的详细对比

1.Thread和Task的详细对比

[2.Task 与 async/await 的配合使用](#2.Task 与 async/await 的配合使用)

[3. async/await 的实际应用场景](#3. async/await 的实际应用场景)

4.关键区别总结


引言:在 C# 编程中,多线程和异步编程都是用于提高应用程序性能和响应性的技术,但它们的用途和实现方式有所不同

一.多线程和异步的区别

1.多线程

定义:

  • 多线程是指在一个应用程序中同时运行多个线程,每个线程都独立执行代码.这些线程可能在多个处理器核心上并行运行,也可能在单个核心上通过时间片轮转方式运行

特性:

  • 并行执行:多个线程可以并行执行任务,提高 CPU 利用率,适用于 CPU 密集型任务
  • 共享内存空间:同一进程中的线程共享内存空间,可以方便地共享数据,但也需要处理同步问题
  • 线程管理:需要开发者手动管理线程的创建,启动,同步和销毁

使用场景:

  • 需要并行处理多个 CPU 密集型任务,以充分利用多核 CPU 的能力
  • 需要在后台执行复杂计算,同时保持应用程序的响应性

2.异步编程

定义:

  • 异步编程是一种编程范式,允许程序在等待长时间运行的操作(如 I/O、网络请求)完成时,不阻塞当前线程,从而提高应用程序的响应性和效率

特性:

  • 非阻塞:异步操作不会阻塞线程,当前线程可以继续执行其他任务
  • 事件驱动:通过回调,事件或任务的方式在操作完成时通知应用程序
  • 适用于 I/O 密集型任务:特别是磁盘,网络等 I/O 操作,这些操作等待时间长,CPU 利用率低

使用场景:

  • 防止界面卡顿:在 GUI 应用程序中,防止长时间的操作阻塞 UI 线程,保持界面响应性
  • 服务器高并发:在服务器应用中,异步操作可以处理大量并发 I/O 请求,提高吞吐量

多线程和异步的区别

cs 复制代码
// 多线程示例
public void ThreadMethod()
{
    // 创建新线程
    Thread thread = new Thread(() =>
    {
        // 这段代码在新线程上运行
        DoSomeWork();
    });
    thread.Start();
}

// 异步示例
public async Task AsyncMethod()
{
    // 不会创建新线程,而是在当前线程上异步执行
    await Task.Run(() =>
    {
        DoSomeWork();
    });
}
  • 目的不同:多线程主要用于并行执行 CPU 密集型任务,异步编程主要用于非阻塞地执行 I/O 密集型任务

  • 实现方式:多线程通过创建和管理线程实现并行,异步编程通过非阻塞的操作和回调机制实现,不一定需要多线程

  • 资源利用 :多线程可能会创建大量线程,占用系统资源;异步编程通常使用回调或任务,不需要额外的线程

    cs 复制代码
    // 多线程示例 - CPU密集型计算
    public void ThreadExample()
    {
        Thread calculateThread = new Thread(() =>
        {
            // 复杂计算
            for (int i = 0; i < 1000000; i++)
            {
                // 进行大量计算
            }
        });
        calculateThread.Start();
    }
    
    // 异步示例 - I/O操作
    public async Task AsyncExample()
    {
        // 读取文件
        string content = await File.ReadAllTextAsync("file.txt");
        // 发送网络请求
        var response = await httpClient.GetAsync("http://api.example.com");
    }

二.Thread,Task和async/await关键字的区别

1.Thread

定义:

  • **System.Threading.Thread**类表示 .NET 中的一个线程,可以用来手动创建,控制和管理线程

特性:

  • 直接映射到操作系统线程 :每个**Thread**实例对应一个操作系统线程
  • 手动管理:需要手动创建,启动和销毁线程,以及处理线程同步问题
  • 开销较大:创建和销毁线程的开销较大,过多的线程可能导致系统性能下降

使用场景:

  • 需要对线程有精细的控制,比如设置线程优先级,堆栈大小,文化信息等
  • 特定场景下需要手动管理线程的生命周期

示例代码:

cs 复制代码
    // 创建第一个线程
    Thread thread1 = new Thread(() =>
    {
        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine($"线程1正在执行: {i}");
            Thread.Sleep(2000); // 暂停2秒
        }
    });

    // 创建第二个线程
    Thread thread2 = new Thread(new ThreadStart(Thread2Method));

    // 启动线程
    Console.WriteLine("开始执行线程...");
    thread1.Start();
    thread2.Start();

    // 等待线程结束
    //Join方法用于等待线程结束,即等待线程中的代码执行完毕。
    thread1.Join();
    thread2.Join();

    Console.WriteLine("所有线程执行完毕!");
    Console.ReadKey();
}

// 第二个线程要执行的方法
static void Thread2Method()
{
    for (int i = 0; i < 5; i++)
    {
        Console.WriteLine($"线程2正在执行: {i}");
        Thread.Sleep(800); // 暂停0.8秒
    }
}

2.Task

定义:

  • **System.Threading.Tasks.Task**类代表一个异步操作,可以理解为更高级别的异步编程抽象

特性:

  • 基于任务的异步模式(TAP):使用任务来表示异步操作,可以更方便地组合,链接和处理任务
  • 线程池Task 默认会使用线程池中的线程,而不是创建新的线程,从而减少开销
  • 支持结果值 :**Task<TResult>**可以返回计算结果
  • async/await 协同工作Task 可以与**async/await**关键字配合使用,简化异步编程

使用场景:

  • 执行异步操作,无需手动管理线程。

  • 需要组合多个异步操作,或处理异步操作的结果。

    cs 复制代码
     static async Task Main(string[] args)
            {
                Console.WriteLine("开始任务示例...");
    
                // 1. 基本的异步任务
                await SimpleTaskAsync();
    
                // 2. 带返回值的任务
                int result = await CalculateAsync();
                Console.WriteLine($"计算结果: {result}");
    
                // 3. 并行任务
                await ParallelTasksAsync();
    
                // 4. 任务超时处理
                await TaskWithTimeoutAsync();
    
                Console.WriteLine("所有任务完成!");
                Console.ReadKey();
            }
    
            // 基本异步任务
            static async Task SimpleTaskAsync()
            {
                Console.WriteLine("开始简单任务");
                await Task.Delay(1000); // 模拟耗时操作
                Console.WriteLine("简单任务完成");
            }
    
            // 带返回值的异步任务
            static async Task<int> CalculateAsync()
            {
                Console.WriteLine("开始计算");
                await Task.Delay(2000); // 模拟复杂计算
                return 42;
            }
    
            // 并行任务示例
            static async Task ParallelTasksAsync()
            {
                Console.WriteLine("开始并行任务");
                
                var task1 = Task.Run(async () =>
                {
                    await Task.Delay(1000);
                    Console.WriteLine("任务1完成");
                });
    
                var task2 = Task.Run(async () =>
                {
                    await Task.Delay(2000);
                    Console.WriteLine("任务2完成");
                });
    
                // 等待所有任务完成
                await Task.WhenAll(task1, task2);
                Console.WriteLine("所有并行任务完成");
            }
    
            // 带超时的任务
            static async Task TaskWithTimeoutAsync()
            {
                Console.WriteLine("开始超时任务");
                
                try
                {
                    using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(2));
                    await Task.Delay(3000, cts.Token); // 这个任务会超时
                    Console.WriteLine("此行不会执行");
                }
                catch (TaskCanceledException)
                {
                    Console.WriteLine("任务已超时");
                }
            }

3.async/await

定义:async/ **await**是 C# 中用于简化异步编程的关键字

特性:

  • async 方法 :使用 async 修饰的方法表示其内部可能包含异步操作,可以使用 **await**关键字
  • await 关键字:用于等待一个异步任务完成,而不会阻塞当前线程
  • 编译器支持 :编译器会将 **async**方法转换为状态机,处理异步操作的调度

使用场景:

  • 希望以同步的方式编写异步代码,提高代码的可读性和维护性。
  • 在 GUI 或服务器应用中,防止长时间的操作阻塞线程。

三.Thread,Task和async/await关键字的详细对比

1.Thread和Task的详细对比

cs 复制代码
// Thread 示例
Thread thread = new Thread(() =>
{
    Console.WriteLine("使用 Thread 执行工作");
    Thread.Sleep(1000);
});
thread.Start();

// Task 示例
Task task = Task.Run(() =>
{
    Console.WriteLine("使用 Task 执行工作");
    Thread.Sleep(1000);
});

主要区别:

Thread:

  • 直接映射到操作系统线程
  • 资源开销大
  • 无法直接返回结果
  • 不易于管理和组合

Task:

  • 使用线程池
  • 可以返回结果
  • 支持取消、延续、异常处理
  • 易于组合和管理

2.Task 与 async/await 的配合使用

cs 复制代码
// Task 单独使用
public Task<int> GetDataAsync()
{
    return Task.Run(() => 
    {
        // 执行一些耗时操作
        Thread.Sleep(1000);
        return 42;
    });
}

// 使用 async/await
public async Task<int> GetDataAsyncWithAwait()
{
    Console.WriteLine("开始");
    await Task.Delay(1000); // 异步等待
    Console.WriteLine("结束");
    return 42;
}

3. async/await 的实际应用场景

cs 复制代码
// 文件操作示例
public async Task SaveFileAsync(string content)
{
    Console.WriteLine("开始保存文件");
    await File.WriteAllTextAsync("test.txt", content);
    Console.WriteLine("文件保存完成");
}

// 多个异步操作组合
public async Task ProcessDataAsync()
{
    try
    {
        // 并行执行多个异步操作
        var task1 = Task.Delay(1000);
        var task2 = Task.Delay(2000);
        
        await Task.WhenAll(task1, task2);
        
        // 串行执行异步操作
        var result1 = await GetDataAsync();
        var result2 = await ProcessResultAsync(result1);
    }
    catch (Exception ex)
    {
        Console.WriteLine($"错误: {ex.Message}");
    }
}

4.关键区别总结

1)执行模型:

  • Thread: 一个线程执行一个任务
  • Task: 可以使用线程池,更灵活
  • async/await: 不创建新线程,而是管理异步操作

2)资源使用:

  • Thread: 每个线程占用约1MB内存
  • Task: 更轻量级,共享线程池
  • async/await: 几乎没有额外开销

3)使用场景:

  • Thread: 需要直接控制线程时
  • Task: 执行后台操作,需要返回结果时
  • async/await: IO操作,网络请求等不需要CPU计算的操作

4)代码可维护性:

  • Thread: 较难管理和维护
  • Task: 提供更好的控制和组合
  • async/await: 提供最清晰的代码结构

在实际的开发中优先使用 async/await 处理异步操作,需要并行计算时使用 Task,只在特殊情况下使用 Thread

相关推荐
鸡啄米的时光机1 分钟前
文生图扩散模型学习资源
学习
诸神缄默不语6 分钟前
里氏替换原则(Liskov Substitution Principle,LSP):面向对象设计的基本原则
开发语言·里氏替换原则
0xCC说逆向24 分钟前
Windows图形界面(GUI)-QT-C/C++ - QT控件创建管理初始化
c语言·开发语言·c++·windows·qt·mfc·sdk
臣妾写不来啊32 分钟前
AI学习之自然语言处理(NLP)
人工智能·学习·自然语言处理
pchmi1 小时前
C# OpenCV机器视觉:振动频率测量
人工智能·opencv·计算机视觉·c#·opencvsharp
ptc学习者1 小时前
用sql 基线 替换执行计划
java·开发语言·ffmpeg
NoneCoder1 小时前
JavaScript系列(22)--模块化进阶
开发语言·javascript·ecmascript
shinelord明2 小时前
【再谈设计模式】模板方法模式 - 算法骨架的构建者
开发语言·数据结构·设计模式·软件工程
go54631584652 小时前
matlab实现了一个优化的遗传算法,用于求解注汽站最优位置的问题
开发语言·matlab
Static_Xiao2 小时前
C语言导航 7.2函数的调用
c语言·开发语言