.NET 中的多线程编程

作者:微信公众号:【架构师老卢】
3-18 9:51
24

概述:在今天的文章中,我将尝试为您提供有关 .NET 中多线程编程的基本信息。我之所以说基本,是因为您可以根据自己的需要使用和阐述这项技术。我将解释同步异步编程中的工作原理以及如何使用方法。如果你准备好了,让我们开始吧!首先,我们需要谈谈 .NET 中的“**线程”**是什么:线程是操作系统进程中的一个独立工作单元。线程允许程序同时执行多个任务或进程。进程是在应用程序运行时启动的基本执行单元,一个进程中可以有多个线程。以及一点点同步和异步编程:在 .net 中,有一个执行操作的主线程。在同步编程中,此主线程在进程完成之前被阻塞,并且不用于其他任务。在异步编程中,当进程被重定向到另一个阶段时,线程将被

在今天的文章中,我将尝试为您提供有关 .NET 中多线程编程的基本信息。我之所以说基本,是因为您可以根据自己的需要使用和阐述这项技术。我将解释同步异步编程中的工作原理以及如何使用方法。

如果你准备好了,让我们开始吧!

首先,我们需要谈谈 .NET 中的“**线程”**是什么:

线程是操作系统进程中的一个独立工作单元。线程允许程序同时执行多个任务或进程。进程是在应用程序运行时启动的基本执行单元,一个进程中可以有多个线程。

以及一点点同步和异步编程:

在 .net 中,有一个执行操作的主线程。在同步编程中,此主线程在进程完成之前被阻塞,并且不用于其他任务。

在异步编程中,当进程被重定向到另一个阶段时,线程将被释放,可以查看其他进程。

服务员 — 餐厅示例

解释同步的最好例子之一——异步编程是服务员和餐厅的例子:

_同步编程_的一个例子是,餐厅的服务员在接受顾客的订单后,等待厨师将订单交付给顾客。当我们将这个例子改编为_同步编程_时,我们解释说,在服务员将顾客的订单交给厨师后,他可以接受其他顾客的订单。

_同步编程_是一种编程方法,其中操作按顺序和逐步运行。一个进程在下一个进程完成之前不会完成,进程通常会相互等待。这可能会导致等待进程完成的时间浪费,尤其是当需要同时运行大量进程时。

_异步编程_是一种编程方法,它允许程序同时运行其进程或任务。异步编程的主要目标是同时启动多个进程,并在等待这些进程的结果的同时处理其他任务。这对于提高应用程序性能和改善用户体验尤为重要。

现在,有几个定义:

**Task:**是返回类型。这实际上就像一个承诺。这意味着操作可能不会立即完成,但如果完成,就会有回报。Task

**异步:**如果方法被标记为 ,则该方法被视为异步方法,并且可以使用其中的 await 关键字等待异步操作。async

等待: 指定该异步调用的预期结果。在这里,如果操作不完整,无论需要多长时间,都将等待它。await

多线程编程

事实上,多线程编程与同步异步编程没有直接关系。但我认为在继续进行多线程编程之前,它作为初步信息是有用的。

_多线程编程_是一种编程方法,它允许软件应用程序同时在多个线程中运行。线程是进程中的独立执行单元,使程序的代码能够并行执行。这可以提高应用程序的性能,更有效地利用多核处理器,并异步处理某些任务。

在威奇的情况下?

看看多线程编程的定义,没有理由不在所有情况下都使用它。特别是在当今的多核和功能强大的计算机中,此选项可能非常有吸引力。但!

在进行多线程编程时,框架本身消耗的资源比平时要多,因为它将你交给它的工作分成几个部分,并为每个部分分配一个单独的线程。您需要密切关注线程管理、同步和可能的问题,例如争用条件。否则,您将损失超过您想要获得的性能。我们稍后会讨论这些,但让我们谈谈应该选择多线程编程的最合适的情况:

  1. **长时间运行的进程:**如果应用程序具有长时间运行的进程(例如,读取或写入大型文件、复杂的数学计算),则并行运行这些进程可以增加应用程序响应时间并提高性能。
  2. **UI 响应:**使用图形用户界面 (UI) 时,务必在不影响用户体验的情况下在后台运行长时间运行的进程。这样可以防止应用程序冻结或无响应。
  3. **并发进程:**当您需要同时管理多个进程时(例如,当多个用户同时在线时),多线程编程非常重要。您可以通过在单独的线程中运行每个进程来实现并行化。

TPL(任务并行库)

TPL 是一个库,它提供了一组用于并行编程、异步操作和线程管理的 API 和工具。TPL 的主要目标是提高多处理器系统的处理性能,并使并行编程更容易、更高效。

让我们看一下这个库中的几个方法:

Parallel.ForEach(): 是一种允许您在集合或数组上创建并行循环的方法。此方法自动管理并行线程以处理集合的每个元素,帮助您更快地完成操作。使用此方法时需要小心:我们给此方法的列表必须是一个庞大的列表。在低元素计数列表中,此方法的运行速度可能比同步方法慢。

        List<int> numbers = Enumerable.Range(1, 1000).ToList();

        Parallel.ForEach(numbers, (number) =>
        {
            Console.WriteLine($"Number: {number}, Thread ID: {Task.CurrentId}");
        });

        Console.WriteLine("Done!");

在此示例中,我们简单地创建了一个从 1 到 1000 的数字列表,并将此列表中的每个数字划分为并行线程,以通过增加使用的内核数来加快该过程。在此示例中,每个数字都可以定义为您需要在循环中执行的作业。通过观察每个数字被分配了不同的线程 ID,我们可以看到框架如何在内部处理这个问题。

您可以看到,由于多线程,没有任何顺序

正如您在上面的示例中看到的,在并行处理中,操作不是按顺序完成的。这是我们可能面临的最重要的问题:

竞争条件

争用条件是指在多线程编程中遇到的情况,其中多个线程试图同时访问同一资源或数据。当多个线程尝试同时修改或读取相同的数据时,就会发生这些情况,并且不能保证按特定顺序工作。

为了克服这种情况,我们需要做的就是使用这种方法。Interlocked.Add()

此方法可帮助我们安全地递增或递减多线程编程中变量的值。这样可以防止多个线程干扰同一进程。

        List<int> numbers = Enumerable.Range(1, 1000).ToList();
        long total = 0;

        Parallel.ForEach(numbers, (number) =>
        {
            Console.WriteLine($"Number: {number}, Thread ID: {Task.CurrentId}");
            Interlocked.Add(ref total, number);
        });

        Console.WriteLine($"Total: {total}");

在这里,Interlocked.Add() 方法实际上阻止了线程同时访问“total”变量。这可以防止两个线程同时读取和递增总数,从而防止可能导致错误结果或数据完整性问题的争用条件。这里不容忽视的一点是,“Interlocked.Add()”也要付出巨大的代价。

另一种方法:

Parallel.For(): 我认为没有必要对这种方法进行额外的解释,因为 Parallel.ForEach() 和此方法之间的差异与 For 和 Foreach 之间的差异相同。

到目前为止得出的结论

到目前为止,我们已经讨论了多线程编程的工作原理、何时使用它以及可能出现的问题。
选择此方法时,应确保确实需要此方法,最重要的是,应执行性能测试。因为正如我之前提到的,在许多情况下,多线程编程的性能可能比正常情况更差。相应地编写代码非常重要。

关于性能的一点

我们提到,由于竞争条件,我们需要锁定多线程操作中使用的数据,并确保其他线程无法对这些数据进行操作。我们还提到,就性能而言,此操作成本高昂。现在让我们来看看如何使用多线程编程来提高性能。

我们先看一下代码:

List<int> numbers = Enumerable.Range(1, 1000).ToList();
int total = 0;

Parallel.ForEach(numbers, () => 0, (x, loop, subtotal) =>
{
    subtotal += x;
    return subtotal;
},(y)=> Interlocked.Add(ref total,y));

Parallel.ForEach() 的参数如下:

*第一个参数是数字,即要处理的集合。

*第二个参数是一个函数,表示在每个线程启动之前要启动的操作。此操作使用每个线程来计算其本地总和。因此,当每个线程开始自己的计算时,此操作从 0 开始。

*第三个参数是表示处理每个项目的进程的函数。每个线程都使用此函数来计算其局部总和返回值。

*第四个参数用于将线程的本地总和添加到主聚合中。这是使用 Interlocked.Add() 方法完成的。
线程在处理每个项目时有一个称为 subtotal 的局部变量。此变量存储每个线程的本地总数。

每个线程计算其局部总和并返回结果 subtotal。

使用 Interlocked.Add() 方法,将每个线程计算的局部总计安全地添加到主总计变量中。

乍一看可能有点复杂,但一旦你使用它,你就会更好地理解它的逻辑。

相关留言评论
昵称:
邮箱:
阅读排行