C# 中的多线程:优点、基础知识和最佳实践

已发表: 2023-06-01

目录

什么是多线程编程

多线程是软件工程中的一个基本概念。 在 C# 中,多线程编程对于使用 .NET Framework 的软件开发人员来说是必不可少的。 开发人员广泛使用C# 中的多线程,因为它允许他们高效地创建复杂且响应迅速的应用程序。

此博客概述了 C# 多线程,同时还介绍了程序员如何轻松创建和管理线程。 它还包括使用多线程和 C# 中可用的不同线程模型的好处。

多线程编程的好处和优势

同时执行时,多线程可提高应用程序的效率。 C# 线程最常见的好处包括:

  • 增强的应用程序性能:在多线程的帮助下,多个任务在同一空间中运行时,应用程序运行速度更快。总的来说,它减少了执行时间并让位于多个任务。
  • 提高吞吐量: C# 中的多任务处理提高了应用程序的吞吐量。当两个不同的线程同时运行时,可以节省时间和资源。
  • 改进的响应能力:在多线程的帮助下,用户可以在程序在后台运行时访问应用程序的前端。
  • 提高资源利用率:多线程允许用户更有效地访问系统资源。例如,线程可以共享文件、内存和 I/O 设备等资源,从而为提高效率铺平道路。
  • 更易于编程:多线程使编程更容易,因为用户可以独立编写线程。它还使用户能够单独调试和测试应用程序。
  • 优化的通信:线程同步可以实现更好的进程间通信。它可用于线程之间更易于访问的通信。

首先,它影响可以同步的单个对象。 其次,它可以与 System.Threading 和 Interlocked 类一起使用。

C#中多线程的基本概念

多线程使用户能够在多个处理器内核的帮助下同时执行多项任务。 以下是多线程中使用的基本概念:

  • 线程:线程是多线程中帮助执行进程的基本单元。这些是给定程序中的执行路径,可以与其他线程并发运行。

在C#中,我们可以找到两种类型的线程,即前台线程和后台线程。 一般的线程类包括名称、优先级、isAlive、ThreadState、Start()、Suspend()、Resume() 和 Join()。

  • 线程池:线程池是帮助执行任务的线程。它允许操作系统重用现有线程并将可能的开销风险降至最低。
  • 同步:同步是忽略对多个操作的其他线程的访问。这是维护数据完整性和防止开销的重要过程。
  • 死锁:死锁是当两个线程共享资源并尝试继续但未成功时发生的错误。它可能导致系统冻结甚至导致等待时间。
  • 异步编程:异步编程允许在后台运行多个任务,同时允许主线程不间断地运行。它为多响应用户界面铺平了道路,增强了应用程序性能。

创建和运行线程

使用这些示例可以更轻松地创建和运行。 下面给出了一个C# 多线程示例

使用系统;

使用系统线程;

类程序{

静态无效主要(){

int workerIndex = 0;

线程 workerThread = new Thread(new ThreadStart(Worker));

workerThread.Start();

对于 (int mainIndex = 1; mainIndex <= 10; mainIndex++) {

Console.WriteLine(“主线程:{0}”, mainIndex);

线程.睡眠(200);

}

workerThread.Join();

}

静态无效工人(){

for (int workerIndex = 1; workerIndex <= 10; workerIndex++) {

Console.WriteLine(“工作线程:{0}”, workerIndex * 2);

线程.睡眠(200);

}

}

}

输出:

主线程:1

工作线程:2

主线程:2

工作线程:4

主线程:3

工作线程:6

主线程:4

工作线程:8

主线程:5

工作线程:10

主线程:6

工作线程:12

主线程:7

工作线程:14

主线程:8

工作线程:16

主线程:9

工作线程:18

主线程:10

工作线程:20

解释:在这个输出中,两个线程同时打印数字 1 到 10 和 2 到 20,后者从循环索引中加倍。在本示例中,使用了C# 线程休眠(Thread.Sleep) 方法。

同样的,我们来看另一个使用前台线程的C#线程例子

使用系统;

使用系统线程;

类程序{

静态无效主要(){

线程 myThread = new Thread(Worker);

我的线程。开始();

Console.WriteLine(“主线程:已启动”);

对于 (int i = 1; i <= 5; i++) {

Console.WriteLine(“主线程:计数 {0}”, i);

线程.睡眠(500);

}

Console.WriteLine(“主线程:结束”);

}

静态无效工人(){

对于(j = 1;j <= 5;j++){

Console.WriteLine(“工作线程:计数{0}”, j * 3);

线程.睡眠(750);

}

Console.WriteLine(“工作线程:结束”);

}

}

输出:

主线程:开始

工作线程:计数 3

主线程:计数 1

工作线程:计数 6

主线程:计数 2

工作线程:计数 9

主线程:计数 3

工作线程:计数 12

主线程:计数 4

工作线程:计数 15

主线程:计数 5

工作线程:已结束

主线程:结束

说明:此输出显示两个线程如何同时工作。由于主线程和后台线程并行工作,主线程打印从 1 到 5 的数字。工作线程打印 3 到 15 的倍数。

查看 upGrad 的软件开发课程以提高技能。

阅读我们与软件开发相关的热门文章

为什么要学习编码? 如何学习编码? 如何安装特定版本的 NPM 包? C++ 中的继承类型 你应该知道什么?

线程同步

线程同步涉及程序中多个线程的集体协调。 它确保程序以特定顺序执行,从而可以访问共享资源。

在 C# 中,它是使用 lock 关键字、同步对象和 Interlocked 类等同步原语完成的。

下面给出一个C#线程同步的例子:

使用系统;

使用系统线程;

类 TablePrinter

{

公共无效打印表()

{

锁定(这个)

{

对于 (int i = 3; i <= 8; i++)

{

线程.睡眠(200);

控制台.WriteLine(i*5);

}

}

}

}

课程计划

{

public static void Main(string[] args)

{

TablePrinter tp = new TablePrinter();

Thread t1 = new Thread(new ThreadStart(tp.PrintTable));

Thread t2 = new Thread(new ThreadStart(tp.PrintTable));

t1.开始();

t2.开始();

}

}

输出:

15

20

25

30

35

40

45

50

55

60

探索我们的软件开发免费课程

云计算基础 从零开始的 JavaScript 基础 数据结构和算法
区块链技术 初学者反应 核心 Java 基础知识
爪哇 初学者的 Node.js 高级JavaScript

死锁

当至少两个或两个以上的线程依赖于一组资源时,就会发生多线程死锁。 当一个线程与求助路径重叠而另一个线程试图做同样的事情时,就会变成死锁。

例如,如果线程 A 锁定了资源 1 并正在等待访问资源 2,而线程 B 正在等待资源 1,则可能会导致死锁。

下面给出一个例子:

使用系统;

使用系统线程;

命名空间 deadlockincsharp

{

公共课范例

{

静态只读对象 firstLock = new object();

静态只读对象 secondLock = new object();

静态无效 ThreadJob()

{

Console.WriteLine(“\t\t\t\tLocking firstLock”);

锁(firstLock)

{

Console.WriteLine(“\t\t\t\tLocked firstLock”);

线程.睡眠(1500);

Console.WriteLine(“\t\t\t\tLocking secondLock”);

锁(secondLock)

{

Console.WriteLine(“\t\t\t\tLocked secondLock”);

}

Console.WriteLine(“\t\t\t\t释放了secondLock”);

}

Console.WriteLine(“\t\t\t\t释放了第一个锁”);

}

静态无效主要()

{

新线程(新线程启动(ThreadJob))。开始();

线程.睡眠(1000);

Console.WriteLine(“锁定 secondLock”);

锁(secondLock)

{

Console.WriteLine(“锁定secondLock”);

Console.WriteLine("Locking firstLock");

锁(firstLock)

{

Console.WriteLine("Locked firstLock");

}

Console.WriteLine(“释放了firstLock”);

}

Console.WriteLine(“释放了secondLock”);

控制台.Read();

}

}

}

输出:

加锁secondLock

锁定secondLock

先上锁Lock

先上锁Lock

释放第一个锁

释放第二个锁

需求软件开发技能

JavaScript 课程 核心 Java 课程 数据结构课程
Node.js 课程 课程 全栈开发课程
NFT课程 开发运营课程 大数据课程
React.js 课程 网络安全课程 云计算课程
数据库设计课程 Python 课程 加密货币课程

线程池

线程池有助于在 C# 的多线程环境中管理多个执行线程。 这些确保所有线程都可以访问受控资源而不会引起死锁。

线程池管理器负责管理线程池,负责创建、销毁和调度线程。

下面是一个使用 TPL(任务并行库)的线程池示例:

使用系统;

使用 System.Threading.Tasks;

课程计划

{

静态无效主要()

{

任务<字符串> task = Task.Factory.StartNew<字符串>

(() => DownloadString(“http://www.example.com/”));

字符串结果 = task.Result;

控制台.WriteLine(结果);

控制台.Read();

}

静态字符串 DownloadString(字符串 uri)

{

使用 (var wc = new System.Net.WebClient())

返回 wc.DownloadString(uri);

}

输出:

输出取决于网页上可用的内容。 该程序将确保从指定 URL 的网页下载内容。 然后它将打印它们。

使用任务并行库 (TPL) 进行异步编程

任务并行库 (TPL) 是处理 APIS 和公共类型的强大工具。 它处理System.ThreadingSystem.Threading.Tasks

.NET Framework 4 为旨在编写并行代码的开发人员提供了语言和框架级别的 API。 在 TPL 的帮助下,异步编程允许程序在不阻塞主线程的情况下运行。

下面是使用 TPL 进行异步编程的示例:

任务<字符串> task = Task.Factory.StartNew<字符串>(() => {

返回“结果”;

});

字符串结果 = task.Result;

异步任务 MyMethod() {

字符串结果=等待任务;

}

查看我们的免费技术课程,在竞争中脱颖而出。

C# 中多线程的最佳实践

就性能和多任务处理而言,多线程可以节省时间。 要了解有关多线程如何工作的更多信息,您可以选择LJMU 的计算机科学理学硕士学位

这里有一些最佳实践可以帮助用户节省时间并记录最高效率。

  • 利用线程安全的集合: .NET Framework 的并发集合为每个集合提供线程安全的版本,这使得多线程更容易高效地工作。这些集合包括列表和查询,以及字典。
  • 实现线程同步:由于线程工具的特性,用户可以快速实现锁、监视器和信号量。
  • 使用线程池:多线程对于系统来说可以更容易和更有效,这要归功于用户完成的绝大多数线程池。同时,用户可以使用它来自动创建线程。
  • 使用线程本地存储:在练习多线程时,通过优化线程本地存储和提供对多个线程的访问来确保对特定资源的访问。
  • 避免共享可变状态:共享可变状态只会导致错误和竞争条件,这可能很棘手。确保不惜一切代价避免可变状态。
  • 使用异步模型:异步方法可帮助您并行执行多个任务,而无需重新启动它们或将它们留在队列中。
  • 避免死锁:使用多线程执行程序时可能会出现死锁。编写程序时,尝试一个线程接一个线程运行,避免死锁。
  • 使用取消令牌:取消令牌允许线程无问题地终止并避免死锁。

探索我们的热门软件工程课程

LJMU & IIITB 计算机科学硕士 加州理工学院 CTME 网络安全证书课程
全栈开发训练营 区块链PG项目
全栈开发中的执行 PG 计划
在下面查看我们所有的课程
软件工程课程

结论

C# 中的多线程仍然是一个基本概念,其高效模型正在发挥作用。 它为程序员提供了一种灵活的方式,可以将程序的工作负载划分为多个并发且独立运行的任务。

虽然多线程可能非常有益,但如果不小心实施,它可能会导致潜在的障碍。

2009 年至 2023 年间,全球用于企业软件的预算超过8560 亿美元,软件开发为开发人员带来了光明的职业生涯。

立即申请upGrad 的全栈软件开发训练营 全栈开发课程可以成为想要释放计算机科学潜力的开发人员的垫脚石。

1.什么是多线程编程?

多线程编程是涉及同时使用多个线程执行程序的过程。 它使前端用户可以不间断地使用计算机上运行的程序的多个副本。

2. 线程和进程的主要区别是什么?

进程通常涉及处于执行状态的程序,而线程由子进程中的进程组成。

3. C#中线程和任务有什么区别?

C# 中的线程负责构建和管理用于编程的线程池。 另一方面,任务表示在后台运行的异步函数。