Python多线程

Python并发与并行

Python并发与并行详细操作教程
并发和并行性都用于多线程程序,但是它们之间的相似性和差异却引起很多困惑。在这方面的一个大问题:并发并行性与否?尽管这两个术语看起来非常相似,但是对以上问题的回答是"否",但并发性和并行性并不相同。现在,如果它们不相同,那么它们之间的基本区别是什么?
简单地说,并发处理从不同线程管理对共享状态的访问,另一方面,并​​行处理涉及利用多个CPU或其内核来提高硬件性能。

详细并发

并发是两个任务在执行中重叠时。可能是应用程序同时在多个任务上进行的情况。我们可以用图解的方式理解它;多个任务正在同时进行,如下所示-
多线程

并发级别

在本节中,我们将在编程方面讨论三个重要的并发级别-

低级并发

在这种并发级别中,显式使用了原子操作。我们不能使用这种并发来构建应用程序,因为它很容易出错并且很难调试。甚至Python也不支持这种并发。

中级并发

在这种并发中,不使用显式原子操作。它使用显式锁。 Python和其他编程语言支持此类并发。大多数情况下,应用程序程序员会使用这种并发性。

高级并发

在这种并发中,既不使用显式的原子操作也不使用显式的锁。 Python具有 concurrent.futures 模块来支持此类并发。

并发系统的属性

要使程序或并发系统正确,必须满足某些属性。与系统终止有关的属性如下-

正确性属性

正确性属性表示程序或系统必须提供所需的正确答案。为了简单起见,我们可以说系统必须正确地将启动程序状态映射到最终状态。

安全财产

安全属性意味着程序或系统必须保持为 "良好" "安全" 状态,并且绝不做任何 "不良"

活力属性

此属性表示程序或系统必须 "取得进展" ,并且它将达到某些理想状态。

并发系统的参与者

这是并发系统的一个共同属性,其中可以有多个进程和线程,它们同时运行以在各自的任务上取得进展。这些进程和线程称为并发系统的参与者。

并发系统资源

演员必须利用内存,磁盘,打印机等资源来执行任务。

某些规则

每个并发系统都必须具有一组规则,以定义参与者要执行的任务的类型以及每个参与者的时间安排。这些任务可能是获取锁,共享内存,修改状态等。

并发系统的障碍

在实现并发系统时,程序员必须考虑以下两个重要问题,这可能是并发系统的障碍-

数据共享

实现并发系统时的一个重要问题是多个线程或进程之间的数据共享。实际上,程序员必须确保锁保护共享数据,以便对它的所有访问都被序列化,并且一次只能有一个线程或进程可以访问共享数据。如果多个线程或进程都试图访问相同的共享数据,则除了其中至少一个线程外,其他所有线程或进程都不会被阻塞并保持空闲状态。换句话说,我们可以说,在强制执行锁定时,我们一次只能使用一个进程或线程。可以有一些简单的解决方案来消除上述障碍-

数据共享限制

最简单的解决方案是不共享任何可变数据。在这种情况下,我们不必使用显式锁定,并且可以解决由于相互数据导致的并发障碍。

数据结构协助

很多时候,并发进程需要同时访问相同的数据。除了使用显式锁之外,另一种解决方案是使用支持并发访问的数据结构。例如,我们可以使用 queue 模块,该模块提供线程安全队列。我们还可以将 multiprocessing.JoinableQueue 类用于基于多处理的并发。

不变的数据传输

有时候,我们使用的数据结构(例如并发队列)不合适,那么我们可以传递不可变的数据而不用锁定它。

可变数据传输

在上述解决方案的延续中,假设如果只需要传递可变数据而不是不变数据,那么我们可以传递只读的可变数据。

共享I/O资源

实现并发系统的另一个重要问题是线程或进程对I / O资源的使用。当一个线程或进程使用I / O的时间如此长,而另一个线程或进程处于空闲状态时,就会出现问题。在使用I / O繁重的应用程序时,我们可以看到这种障碍。可以借助一个示例来理解,即从Web浏览器请求页面。这是一个繁重的应用程序。在这里,如果请求数据的速率比消耗数据的速率慢,那么我们的并发系统就会有I / O障碍。
以下Python脚本用于请求网页并获取网络获取所请求页面所花费的时间-
# Filename : example.py
# Copyright : 2020 By Lidihuo
# Author by : www.lidihuo.com
# Date : 2020-08-22
import urllib.request
import time
# 网站是https访问的需要引入ssl模块
import ssl
# 导入ssl时关闭证书验证
ssl._create_default_https_context = ssl._create_unverified_context
ts = time.time()
req = urllib.request.urlopen('https://www.lidihuo.com')
pageHtml = req.read()
te = time.time()
print("Page Fetching Time : {} Seconds".format (te-ts))
执行上述脚本后,我们可以获取页面获取时间,如下所示。

输出

Page Fetching Time : 0.08858084678649902 Seconds
我们可以看到,提取页面的时间超过了一秒钟。现在,如果我们想获取成千上万个不同的网页该怎么办,您可以了解我们的网络将花费多少时间。

什么是并行性?

并行性可以定义为将任务拆分为可以同时处理的子任务的技术。如上所述,与并发相反,在并发中同时发生两个或更多事件。我们可以用图解的方式理解它;任务分为多个可以并行处理的子任务,如下所示-
平行
要了解并发和并行性之间的区别,请考虑以下几点-

并发但不并行

应用程序可以是并发的,但不能是并行的,这意味着它可以同时处理多个任务,但这些任务不会分解为子任务。

并行但不并行

应用程序可以是并行的,但不能是并发的,这意味着它一次只能处理一个任务,分解为子任务的任务可以并行处理。

既不是并行也不是并行

应用程序不能是并行的,也不能是并行的。这意味着它一次只能处理一个任务,并且该任务永远不会分解为子任务。

并行和并发

应用程序可以是并行的,也可以是并发的,这意味着它一次可以同时处理多个任务,并且该任务被分解为多个子任务以并行执行。

并行性的必要性

我们可以通过在单个CPU的不同内核之间或在网络内连接的多台计算机之间分配子任务来实现并行性。
请考虑以下要点,以了解为什么必须实现并行性-

高效的代码执行

借助并行性,我们可以有效地运行代码。这将节省我们的时间,因为部分中的相同代码可以并行运行。

比顺序计算快

顺序计算受物理和实际因素的限制,因此无法获得更快的计算结果。另一方面,此问题可以通过并行计算解决,并且比顺序计算为我们提供更快的计算结果。

执行时间短

并行处理减少了程序代码的执行时间。
如果我们谈论现实生活中的并行性示例,那么我们计算机的图形卡就是强调并行处理的真正力量的示例,因为它具有数百个独立工作并可以同时执行的独立处理核心。由于这个原因,我们也能够运行高端应用程序和游戏。

了解要实现的处理器

我们了解并发性,并行性以及它们之间的区别,但是有关实现它的系统又如何呢?了解我们将要在其上实施的系统非常必要,因为它使我们受益于在设计软件时做出明智的决定。我们有以下两种处理器-

单核处理器

单核处理器能够在任何给定时间执行一个线程。这些处理器使用 上下文切换在特定时间存储线程的所有必要信息,然后在以后恢复该信息。上下文切换机制可帮助我们在给定的每秒内在多个线程上取得进展,并且看起来系统正在处理多个事情。
单核处理器具有许多优势。这些处理器需要较少的功率,并且多个内核之间没有复杂的通信协议。另一方面,单核处理器的速度受到限制,不适合大型应用程序。

多核处理器

多核处理器具有多个独立的处理单元,也称为
这类处理器不需要上下文切换机制,因为每个内核都包含执行一系列存储指令所需的一切。

获取-解码-执行周期

多核处理器的核心遵循一个执行周期。此循环称为 获取-解码-执行循环。它涉及以下步骤-

获取

这是循环的第一步,其中涉及从程序存储器中获取指令。

解码

最近获取的指令将转换为一系列信号,这些信号将触发CPU的其他部分。

执行

这是将执行已提取和已解码指令的最后一步。执行结果将存储在CPU寄存器中。
此处的一个优点是,多核处理器中的执行速度比单核处理器快。适用于大型应用。另一方面,多个核之间的复杂通信协议是一个问题。多核比单核处理器需要更多的功率。
昵称: 邮箱:
Copyright © 2022 立地货 All Rights Reserved.
备案号:京ICP备14037608号-4