首页 > 编程语言 >C#多线程并发编程深度探索:解锁async、await、Task与lock等关键字的奥秘

C#多线程并发编程深度探索:解锁async、await、Task与lock等关键字的奥秘

时间:2024-08-10 13:55:00浏览次数:12  
标签:异步 Task Thread C# await 线程 多线程 编程

一、多线程介绍

1.什么是多线程

多线程是指在一个应用程序中同时执行多个线程的能力。每个线程都是独立运行的,拥有自己的执行路径和资源。多线程编程能够充分利用多核处理器的计算能力,提高应用程序的性能和响应性,特别是在处理耗时任务和并行计算时效果显著。

在C#中,线程是程序执行流的最小单元,每个线程都拥有独立的执行栈、程序计数器和本地变量。多线程编程允许程序同时执行多个线程,从而实现并发执行,提高程序的执行效率。

2.C#实现多线程的原理

C#实现多线程的原理主要依赖于操作系统对线程的支持和.NET Framework(或.NET Core/.NET 5+)提供的多线程编程模型。以下是一些关键点:

  1. 操作系统支持
    • 现代操作系统(如Windows、Linux等)都提供了对线程的支持,包括线程的创建、调度、同步等机制。
    • 操作系统负责管理线程的生命周期,包括分配CPU时间片给线程执行,以及在线程之间切换执行等。
  2. .NET Framework多线程编程模型
    • Thread类:C#中的System.Threading.Thread类是用于创建和管理线程的主要类。通过实例化Thread类并传递一个委托(如ThreadStartParameterizedThreadStart)给其构造函数,可以指定线程应执行的方法。
    • 线程池(ThreadPool):为了减少线程创建和销毁的开销,.NET Framework提供了线程池。线程池维护了一组工作线程,当需要执行新任务时,线程池会从池中取出一个空闲线程来执行任务,如果池中没有空闲线程,则可能会创建新线程(但受到一定限制)。
    • Task Parallel Library (TPL):TPL是.NET Framework中更高级别的多线程编程模型,它提供了TaskTask<TResult>类来简化异步编程。TPL能够自动管理线程,使得开发者可以更加专注于任务的逻辑,而不是线程的管理。
  3. 线程同步与通信
    • 多线程编程中,线程之间可能需要访问共享资源,这时就需要进行线程同步,以避免数据竞争和死锁等问题。C#中提供了多种同步机制,如锁(lock)、信号量(Semaphore)、互斥锁(Mutex)等。
    • 线程间通信可以通过共享内存、消息队列、事件等方式实现。在C#中,还可以使用Control.InvokeControl.BeginInvoke等方法在WinForms应用程序中从非UI线程更新UI元素。
  4. 异步编程
    • 异步编程是一种特殊的多线程编程方式,它允许在操作进行时释放主线程并继续执行其他任务,待操作完成后再回到主线程继续处理结果。C#中的asyncawait关键字为异步编程提供了强大的支持。

二、多线程实现方法

 

1. 使用Thread

这是最直接的方式,通过实例化System.Threading.Thread类来创建线程。你可以将ThreadStartParameterizedThreadStart委托传递给线程的构造函数,并在该委托中指定线程应执行的方法。

using System;  
using System.Threading;  
  
class Program  
{  
    static void Main(string[] args)  
    {  
        Thread thread = new Thread(new ThreadStart(ThreadMethod));  
        thread.Start();  
  
        // 或者使用带参数的线程  
        Thread threadWithParam = new Thread(new ParameterizedThreadStart(ThreadMethodWithParam));  
        threadWithParam.Start("Hello, Thread!");  
    }  
  
    static void ThreadMethod()  
    {  
        Console.WriteLine("ThreadMethod is running.");  
    }  
  
    static void ThreadMethodWithParam(object param)  
    {  
        Console.WriteLine($"ThreadMethodWithParam is running with parameter: {param}");  
    }  
}

2. 使用Task

从.NET Framework 4.0开始,System.Threading.Tasks命名空间下的Task类提供了更高级别的并行和异步编程模型。TaskThread更易于使用,也更强大,因为它支持取消、等待和继续任务等操作。

using System;  
using System.Threading.Tasks;  
  
class Program  
{  
    static void Main(string[] args)  
    {  
        Task task = Task.Run(() => {  
            Console.WriteLine("Task is running.");  
        });  
  
        task.Wait(); // 等待任务完成  
  
        // 或者使用异步等待  
        // Task.Run(async () => {  
        //     await Task.Delay(1000); // 模拟异步操作  
        //     Console.WriteLine("Task with async operation is running.");  
        // }).Wait();  
    }  
}

3. 使用ThreadPool

线程池(ThreadPool)是一种基于池的线程管理机制,它维护一个线程的集合,这些线程可以被重用,以减少线程创建和销毁的开销。当需要执行一个短时间操作时,使用线程池是一个好选择。

using System;  
using System.Threading;  
  
class Program  
{  
    static void Main(string[] args)  
    {  
        ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadMethod));  
  
        // 等待足够的时间以确保线程池中的线程完成  
        Thread.Sleep(1000);  
    }  
  
    static void ThreadMethod(object state)  
    {  
        Console.WriteLine("Thread from ThreadPool is running.");  
    }  
}

4. 使用asyncawait

asyncawait关键字用于简化异步编程模型。它们允许你以同步的方式编写异步代码,而不需要处理复杂的回调和状态管理。这通常与Task类一起使用。

using System;  
using System.Threading.Tasks;  
  
class Program  
{  
    static async Task Main(string[] args)  
    {  
        await Task.Run(() => {  
            Console.WriteLine("Async operation is running.");  
        });  
  
        Console.WriteLine("Async operation completed.");  
    }  
}

三、不同方式之间的优缺点

在C#中实现多线程的几种方式(Thread类、Task类、ThreadPool以及async/await)之间存在几个关键的区别,这些区别主要体现在创建方式、使用场景、性能表现、功能丰富度以及易用性等方面。

1. Thread类

创建方式

  • 通过实例化System.Threading.Thread类并传递一个ThreadStartParameterizedThreadStart委托来创建线程。

使用场景

  • 适合需要直接控制线程生命周期、优先级等详细行为的场景。
  • 快速启动执行简单任务。

性能表现

  • 每次创建新线程都会有一定的开销,包括分配系统资源。
  • 频繁地创建和销毁线程可能会影响性能。

功能丰富度

  • 提供了对线程进行细致控制的能力,如设置优先级、名称等。

易用性

  • 需要手动管理线程的生命周期和同步问题,代码复杂度较高。

2. Task类

创建方式

  • 使用Task.Run方法或实例化Task类并调用其Start方法(虽然直接实例化并调用Start不是主要用法)。

使用场景

  • 现代.NET应用中推荐的异步编程方式。
  • 需要更好地管理异步操作、任务取消、异常处理等场景。

性能表现

  • 使用线程池来管理线程,减少了线程创建和销毁的开销。
  • 在多核处理器上能够更好地利用并行处理能力。

功能丰富度

  • 提供了丰富的API来管理任务,如等待任务完成、获取任务结果、任务取消等。

易用性

  • 通过async/await关键字可以方便地编写异步代码,降低了异步编程的复杂度。

3. ThreadPool

创建方式

  • 通过ThreadPool.QueueUserWorkItem方法将工作项(通常是一个委托)排入队列,由线程池自动调度执行。

使用场景

  • 需要高效利用线程池资源,执行大量短时间操作的场景。

性能表现

  • 减少了线程创建和销毁的开销,提高了性能。
  • 但由于全局队列的资源竞争,在高负载下可能会受到限制。

功能丰富度

  • 提供了基本的线程管理功能,但相比Thread和Task,控制度较低。

易用性

  • 使用相对简单,但对于复杂的异步操作和任务管理来说,功能可能不够丰富。

4. async/await

创建方式

  • 不是直接创建线程的方式,而是与Task类结合使用,以异步方式执行代码。

使用场景

  • 需要编写清晰、易于维护的异步代码的场景。
  • 适用于I/O密集型操作或需要提高程序响应性的场景。

性能表现

  • 通过异步方式提高了程序的响应性和吞吐量。
  • 在执行异步操作时不会阻塞调用线程。

功能丰富度

  • 提供了强大的异步编程模型,简化了异步代码的编写和维护。

易用性

  • 通过async/await关键字,可以以几乎同步的方式编写异步代码,提高了代码的可读性和可维护性。

综上所述,Thread类、Task类、ThreadPool以及async/await在C#中实现多线程的方式各有其特点和适用场景。在选择使用哪种方式时,应根据具体需求和场景来做出决策。

标签:异步,Task,Thread,C#,await,线程,多线程,编程
From: https://blog.csdn.net/weixin_67244432/article/details/141089999

相关文章

  • Docker搭建多版本PHP环境
    最近由于项目需要,需要同时启动多个项目,但是一个项目是php5.6,一个项目是php7.4,还有一个是php8.0,但是我需要同时运行,所以需要搭建一个多版本的开发环境,基于此自己实现了一个dnmpDNMP是基于docker部署的Nginx、PHP、MySQL开发环境支持php5.6、php7.0、php7.1、php7.2、php7......
  • BugKu CTF Misc:眼见非实 & 啊哒 & ping & Snowfall
    前言BugKu是一个由乌云知识库(wooyun.org)推出的在线漏洞靶场。乌云知识库是一个致力于收集、整理和分享互联网安全漏洞信息的社区平台。BugKu旨在提供一个实践和学习网络安全的平台,供安全爱好者和渗透测试人员进行挑战和练习。它包含了各种不同类型的漏洞场景,如Web漏洞、系统......
  • 【全网独家】libVLC 更改视频宽高比(代码+测试部署)
    libVLC更改视频宽高比介绍libVLC是VLC媒体播放器的核心库,提供了强大的多媒体处理功能。更改视频宽高比(AspectRatio)是指调整视频帧的宽度和高度比例,以适应不同的显示设备或满足特定的播放需求。应用使用场景视频播放器:用户可能需要调整视频的宽高比以适应窗口或全屏......
  • 面向对象编程(OOP: Object Oriented Programming ):类、对象、构造方法、封装
    目录一、类1、定义(1)属性(2)方法2、类的定义方法二、对象1、定义2、对象的定义方法三、类和对象的关系1、现实世界都是由很多对象组成的,基于对象的共同特征抽象出类。2、对象:真实存在的对象3、类是对象的模板,对象是类的具体实例。4、一个类可以创建多个对象,同一个......
  • 【数据结构与算法】输出二叉树中从每个叶子结点到根结点的路径 C++实现(二叉树+栈+深度
    二叉树叶子节点到根节点的路径题目描述给定一棵二叉树的后序遍历序列post[s1..t1]和中序遍历序列in[s2..t2],设计一个算法,输出二叉树中从每个叶子节点到根节点的路径。请使用栈的数据结构解决。输入格式输入包括两行:第一行为后序遍历序列post[s1..t1]。第二行为中序......
  • JDBC数据库连接技术基础及核心API
    目录JDBC的概念JDBC的搭建步骤JDBC的代码实现步骤框架代码实现核心API注册驱动(jdk6.0后可自动注册,无需编写代码)Connection(连接数据库)Statement(用于执行SQL语句,会被SQL注入攻击,后被PreparedStatement替代)PreparedStatement(可以防止SQL注入,全面替代Statement)ResultS......
  • nowcoder Week Contest
    52小红有\(n\)个数字\(a_1,a_2,\dots,a_n\)和一个空字符串\(s\)。现在她需要执行\(n\)次操作:第\(i\)次操作需要将\(a_i\)按照数位上的相对顺序、从左到右的取出并依次插入\(s\)(在\(s\)中不需要连续,但需要保持原有相对顺序)。小红想要构造一个这样的字符串\(s\)......
  • CF844D Boxes And Balls
    题意有\(n\)个箱子、\(n\)种颜色的球,第\(i\)种颜色的球有\(w_i\)个,最开始时都在第\(1\)个箱子中。每次可以从有球的一个箱子中拿出所有球,并随意分割为2部分或3部分,并放入箱子,需要的代价为球的总数。问将每种颜色的球都放在对应的一个箱子中需要的代价最少是多少。......
  • 逆概率采样-接受拒绝采样-MCMC采样
    importnumpyasnpimportscipyfrommatplotlibimportpyplotaspltdefpdf(x):if0<=x<0.25:return8*xelif0.25<=x<1:return8/3-8/3*xelse:return0defcdf(x):ifx<0:......
  • C++类和对象(上)
    文章目录一、类的定义1、类的定义格式2、访问限定符3、类域二、实例化1、实例化概念2、对象的大小三、this指针一、类的定义1、类的定义格式calss是定义类的关键词,用法更C语言中的结构体struct关键词用法一样,区别是类可以在里面创建函数,当然在C++中也是兼容结......