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

news2025/1/16 15:21:29

目录

一.多线程和异步的区别

1.多线程

2.异步编程

多线程和异步的区别

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

1.Thread

2.Task

3.async/await

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

1.Thread和Task的详细对比

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

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

4.关键区别总结


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

一.多线程和异步的区别

1.多线程

定义:

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

特性:

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

使用场景:

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

2.异步编程

定义:

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

特性:

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

使用场景:

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

多线程和异步的区别

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

// 异步示例
public async Task AsyncMethod()
{
    // 不会创建新线程,而是在当前线程上异步执行
    await Task.Run(() =>
    {
        DoSomeWork();
    });
}
  • 目的不同:多线程主要用于并行执行 CPU 密集型任务,异步编程主要用于非阻塞地执行 I/O 密集型任务
  • 实现方式:多线程通过创建和管理线程实现并行,异步编程通过非阻塞的操作和回调机制实现,不一定需要多线程
  • 资源利用:多线程可能会创建大量线程,占用系统资源;异步编程通常使用回调或任务,不需要额外的线程
    // 多线程示例 - 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 实例对应一个操作系统线程
  • 手动管理:需要手动创建,启动和销毁线程,以及处理线程同步问题
  • 开销较大:创建和销毁线程的开销较大,过多的线程可能导致系统性能下降

使用场景:

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

示例代码:

    // 创建第一个线程
    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 关键字配合使用,简化异步编程

使用场景:

  • 执行异步操作,无需手动管理线程。
  • 需要组合多个异步操作,或处理异步操作的结果。
     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的详细对比

// 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 的配合使用

// 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 的实际应用场景

// 文件操作示例
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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2277593.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RTC(Real_Time Clock)

RTC概述&#xff1a; RTC&#xff08;实时时钟&#xff0c;Real-Time Clock&#xff09;是一种用于跟踪当前日期和时间的计时设备。RTC可以是独立的芯片&#xff0c;也可以是集成在微控制器或处理器中的一个模块。RTC是现代电子设备中不可或缺的一部分&#xff0c;为各种应用提…

[leetcode]链表基础回顾

一.创建带头节点的链表 #include <iostream> #include <string> #include <algorithm> using namespace std; typedef struct Node { char ch; Node* next; }*LinkList,ListNode; void printLinkList(LinkList& head) { LinkList p head…

rclone,云存储备份和迁移的瑞士军刀,千字常文解析,附下载链接和安装操作步骤...

一、什么是rclone&#xff1f; rclone是一个命令行程序&#xff0c;全称&#xff1a;rsync for cloud storage。是用于将文件和目录同步到云存储提供商的工具。因其支持多种云存储服务的备份&#xff0c;如Google Drive、Amazon S3、Dropbox、Backblaze B2、One Drive、Swift、…

JAVA:利用 RabbitMQ 死信队列实现支付超时场景的技术指南

1、简述 在支付系统中&#xff0c;订单支付的超时自动撤销是一个非常常见的业务场景。通常用户未在规定时间内完成支付&#xff0c;系统会自动取消订单&#xff0c;释放相应的资源。本文将通过利用 RabbitMQ 的 死信队列&#xff08;Dead Letter Queue, DLQ&#xff09;来实现…

favor的本质

英文单词 favor&#xff0c;通常指一个的“喜好或偏爱”&#xff1a; favor n.赞成&#xff1b;喜爱&#xff0c;宠爱&#xff0c;好感&#xff0c;赞同&#xff1b;偏袒&#xff0c;偏爱&#xff1b;善行&#xff0c;恩惠 v.赞同&#xff1b;喜爱&#xff0c;偏爱&#xff1b…

[青基解读一] 2025年国家自然科学基金---指南解读

指南解读 1 需要2个高级专业技术职称推荐&#xff08;2个正教授&#xff09; 2 国自然、国社科只能申请一个 3 资助类别 亚类说明 附注说明 自由探索or目标导向 4 申请代码到二级 申请代码、研究方向、关键词 主要参与者不写学生仅写人数 主要参与者 在线采集、填写简历、生成…

Open FPV VTX开源之ardupilot配置

Open FPV VTX开源之ardupilot配置 1. 源由2. 配置3. 总结4. 参考资料5. 补充5.1 飞控固件版本5.2 配置Ardupilot的BF OSD5.3 OSD偏左问题 1. 源由 飞控嵌入式OSD - ardupilot配置使用ardupliot配套OSD图片。 Choose correct font depending on Flight Controller SW. ──>…

HarmonyOS应用开发者初级认证最新版– 2025/1/13号题库新版

1.欢迎各位读者&#xff0c;本文档来自鸿蒙开发学员亲测&#xff0c;最新版。&#xff08;考试时直接Ctrlf进行搜索&#xff0c;一定要认真比对答案&#xff0c;有的答案相似度很高&#xff09;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 欢迎…

视觉多模态大模型---MiniMax-vl-01---以闪电般的注意力缩放基础模型

简介 MiniMax-VL-01 是与今年1月15日由上海稀宇科技有限公司&#xff08;MiniMax&#xff09;发布并开源的一款视觉多模态大模型&#xff0c;它与基础语言大模型 MiniMax-Text-01 一同构成了 MiniMax-01 系列。这款模型的设计初衷是为了应对日益增长的长上下文处理需求&#x…

CF 230A.Dragons(Java实现)

题目分析 &#xff08;桐老爷&#xff0c;泪目&#xff09;题目讲很多字&#xff0c;其实就是打怪升级&#xff0c;初始战斗力>龙的战斗力就能击败龙并炼化经验增加战斗力&#xff0c;然后打下一条龙&#xff0c;如果打不过了就寄 思路分析 首先我还是想到键值对&#xff0…

【落羽的落羽 C语言篇】文件操作

文章目录 一、文件的概念和分类1. 概念和分类2. 文件名3. 数据文件 三、文件操作1. 文件的打开和关闭1.1 流1.2 文件指针1.3 文件的打开和关闭 2. 文件的顺序读写3. 文件的随机读写4. 文件读取的判定5. 文件缓冲区 一、文件的概念和分类 1. 概念和分类 文件是用来保存数据的。…

速通Docker === 介绍与安装

目录 Docker介绍 Docker优势 Docker组件 Docker CLI (命令行接口) Docker Host (Docker 守护进程) 容器 (Container) 镜像 (Image) 仓库 (Registry) 关系总结 应用程序部署方式 传统部署 (Traditional Deployment) 虚拟化部署 (Virtualization Deployment) 容器部署…

数据分析:非度量多维排列 NMDS (Non-metric multidimensional scaling)ANOSIM检验分析

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍原理步骤加载R包数据下载导入数据数据预处理计算距离矩阵ANOSIM检验非度量多维排列NMDS应力值(stress value)画图输出系统信息介绍 非度量多维排列(Non-metric Multidimensiona…

Flink (七): DataStream API (四) Watermarks

1. Event Time and Processing Time 1. 1 处理时间&#xff08;Processing time&#xff09; 处理时间是指执行相应操作的机器的系统时间。当流处理程序基于处理时间运行时&#xff0c;所有基于时间的操作&#xff08;如时间窗口&#xff09;将使用执行相应算子的机器的系统时…

OpenStack 网络服务的插件架构

OpenStack 的网络服务具有灵活的插件架构&#xff0c;可支持多种不同类型的插件以满足不同的网络需求。以下是对 OpenStack 网络服务插件架构中一些常见插件类型的介绍&#xff1a; 一、SDN 插件 Neutron 与 SDN 的集成&#xff1a;在 OpenStack 网络服务里&#xff0c;SDN 插…

光伏储能交直流微电网Matlab/Simulink仿真模型

博士毕业后项目和课题的交接工作也都基本上结束了&#xff0c;之前从20年我博一开始创作的博客&#xff0c;我也将从25年伊始重新进行更新&#xff0c;在保留原有内容的基础上&#xff0c;在对现如今的研究热点进行补充&#xff0c;希望能为各位校友提供一定的研究思路。首先是…

【js进阶】设计模式之单例模式的几种声明方式

单例模式&#xff0c;简言之就是一个类无论实例化多少次&#xff0c;最终都是同一个对象 原生js的几个辅助方式的实现 手写forEch,map,filter Array.prototype.MyForEach function (callback) {for (let i 0; i < this.length; i) {callback(this[i], i, this);} };con…

Broker收到消息之后如何存储

1.前言 此文章是在儒猿课程中的学习笔记&#xff0c;感兴趣的想看原来的课程可以去咨询儒猿课堂《从0开始带你成为RocketMQ高手》&#xff0c;我本人觉得这个作者还是不错&#xff0c;都是从场景来进行分析&#xff0c;感觉还是挺适合我这种小白的。这块主要都是我自己的学习笔…

vim使用指南

&#x1f3dd;️专栏&#xff1a;计算机操作系统 &#x1f305;主页&#xff1a;猫咪-9527-CSDN博客 “欲穷千里目&#xff0c;更上一层楼。会当凌绝顶&#xff0c;一览众山小。” 目录 一、Vim 的基本概念 1.Vim 的主要模式&#xff1a; 1.1普通模式 (Normal Mode) 1.2插入…

计算机网络 网络层 2

IP协议&#xff1a; Ip数据报的格式&#xff1a; 首部:分为固定部分 和 可变部分 固定部分是20B 版本&#xff1a;表明了是IPV4还是IPV6 首部长度&#xff1a;单位是 4B&#xff0c;表示的范围是&#xff08;5~15&#xff09;*4B 填充&#xff1a;全0&#xff0c;,让首部变…