并发背后的想法是什么,为什么它有用?
并发是指设计和构造程序命令和指令,以便在共享相同资源的同时,以有效的顺序执行程序的不同部分。
并发编程和顺序编程有什么区别?
在顺序编程中,命令和指令按顺序一次执行一个。在并发编程中,为了获得更好的执行时间,某些部分可能会以有效的方式执行。
并发编程和并行编程有什么区别?
在并行编程中,程序的各个部分相互独立;它们彼此不交互,因此可以同时执行。在并发编程中,不同的任务共享相同的资源,因此需要在它们之间进行某种形式的协调。
每个程序可以并发还是并行?
不
什么是令人尴尬的平行任务?
令人尴尬的并行任务可以分为单独的、独立的部分,很少或根本不需要努力。
什么是固有的顺序任务?
如果任务中各个部分的执行顺序对任务的结果至关重要,则不能使其并发或并行以获得更好的执行时间,则称为固有顺序任务。
I/O 绑定是什么意思?
在这种情况下,完成计算所需的时间主要取决于等待输入/输出操作完成所花费的时间。
当前在现实世界中如何使用并发处理?
并发几乎无处不在:桌面和移动应用、视频游戏、web 和 internet 开发、人工智能等等。
什么是 Amdahl 定律?Amdahl 定律想要解决什么问题?
Amdahl 定律提供了在固定工作负载下执行任务的延迟的理论加速估计值,这对于资源得到改善的系统来说是可以预期的。
解释 Amdahl 定律的公式及其组成部分。
Amdahl 定律的公式如下:
**在上述公式中,以下公式适用:
- S是考虑中的理论加速比。
- B是整个任务中固有顺序的部分。
- j是正在使用的处理器数量。
根据 Amdahl 定律,是否会随着系统资源的改善而无限加速增长?
不随着处理器数量的增加,通过改进获得的效率降低。
Amdahl 定律和收益递减定律之间的关系是什么?
您已经看到,在特定情况下(即,只有处理器数量增加时),Amdahl 定律类似于收益递减定律。具体地说,随着处理器数量的增加,通过改进获得的效率降低,加速曲线变平。
什么是线?线程和进程之间的核心区别是什么?
执行线程是编程命令的最小单位。在同一个进程中可以实现多个线程,通常并发执行并访问/共享相同的资源,如内存,而单独的进程不这样做。
Python 中的thread模块提供了哪些 API 选项?
thread模块的主要特点是其创建新线程以执行函数的快速高效方法:thread.start_new_thread()函数。除此之外,该模块只支持使用多线程原语并共享其全局数据空间的一些低级方法。此外,还提供了用于同步目的的简单锁对象(例如互斥量和信号量)。
**Python 中的threading**模块提供了哪些 API 选项?
除了thread模块提供的处理线程的所有功能外,threading模块还支持许多额外的方法,如下所示:
threading.activeCount():此函数返回程序中当前活动线程对象的数量。threading.currentThread():此函数从调用者返回当前线程控件中线程对象的数量。threading.enumerate():此函数返回程序中所有当前活动线程对象的列表。
通过thread和threading模块创建新线程的过程是什么?
使用thread和threading模块创建新线程的过程如下:
-
在
thread模块中,创建新线程以并发执行函数。方法是使用thread.start_new_thread()函数:thread.start_new_thread(function, args[, kwargs])。 -
要使用
threading模块创建和自定义新线程,需要遵循以下具体步骤:- 在我们的程序中定义
threading.Thread类的一个子类 - 重写子类中的默认
__init__(self [,args])方法,为类添加自定义参数 - 重写子类中的默认
run(self [,args])方法,以便在初始化和启动新线程时自定义 thread 类的行为
- 在我们的程序中定义
使用锁进行线程同步背后的想法是什么?
在给定的程序中,当一个线程正在访问/执行程序的关键部分时,任何其他线程都需要等待,直到该线程完成执行。线程同步的典型目标是避免多个线程访问其共享资源时出现任何潜在的数据差异;一次只允许一个线程执行关键部分可以保证多线程应用中不会发生数据冲突。应用线程同步的最常见方法之一是通过实现锁定机制。
Python 中使用锁实现线程同步的过程是什么?
在我们的threading模块中,threading.Lock类提供了一种简单直观的方法来创建和使用锁。其主要用途包括以下几种方法:
threading.Lock():此方法初始化并返回一个新的锁对象。acquire(blocking):调用此方法时,所有线程将同步运行(即一次只能有一个线程执行临界段)。release():调用此方法时,锁释放。
队列数据结构背后的想法是什么?
队列是一种抽象数据结构,是按特定顺序维护的不同元素的集合;这些元素可以是程序中的其他对象。
排队在并发编程中的主要应用是什么?
队列的概念在并发编程的子领域中更为普遍,因为当多线程程序处理和操纵其共享资源时,队列中维护的元素顺序起着重要作用。
常规队列和优先级队列的核心区别是什么?
优先级队列抽象数据结构类似于队列数据结构,但顾名思义,优先级队列的每个元素都有一个与其关联的优先级;换句话说,当元素添加到优先级队列时,需要指定其优先级。与常规队列不同,优先级队列的出列原则依赖于元素的优先级:优先级较高的元素在优先级较低的元素之前被处理。
什么是文件描述符,用 Python 可以用什么方式处理?
文件描述符用作程序中打开的外部文件的句柄。在 Python 中,文件描述符通过使用open()和close()函数或使用with语句进行处理;例如:
f = open(filename, 'r'); ... ; f.close()with open(filename, 'r') as f: ...
如果文件描述符处理不当,会出现什么问题?
系统只能在一个正在运行的进程中处理一定数量的打开的外部文件。当超过该限制时,打开的文件上的句柄将被破坏,并且将发生文件描述符泄漏。
什么是锁,用 Python 可以用什么方式处理?
锁是并发和并行编程中执行线程同步的机制。在 Python 中,threading.Lock对象可以通过acquire()和release()方法处理,也可以通过with语句处理;例如:
my_lock.acquire(); ... ; my_lock.release()with my_lock: ...
锁操作不小心会出现什么问题?
当获取锁时发生异常时,如果不小心处理,锁将永远无法释放和再次获取,从而导致并发和并行编程中的一个常见问题,称为死锁。
上下文管理器背后的想法是什么?
上下文管理器负责程序内资源的上下文;它们定义和处理其他实体与这些资源的交互,并在程序退出上下文后执行清理任务。
Python 中的with语句在上下文管理方面提供了哪些选项?
Python 中的with语句提供了一种直观方便的方式来管理资源,同时确保正确处理错误和异常。除了更好的错误处理和保证的清理任务外,with语句还提供了程序的额外可读性,这是 Python 为其开发人员提供的最强大的特性之一。
什么是 HTML?
HTML代表超文本标记语言,是开发网页和 web 应用的标准和最常用的标记语言。
什么是 HTTP 请求?
大多数通过互联网(更具体地说,万维网)进行的通信都使用 HTTP。在 HTTP 中,请求方法用于传递有关所请求的数据以及应该从服务器发回的数据的信息。
什么是 HTTP 响应状态码?
HTTP 响应状态代码是三位数,表示服务器与其客户端之间的通信状态。它们分为五类,每一类都表示特定的通信状态。
模块requests如何帮助进行 web 请求?
requests模块通过 HTTP 请求管理 Python 程序与 web 服务器之间的通信。
什么是 ping 测试,通常是如何设计的?
ping 测试是 web 管理员通常使用的一种工具,用于确保其站点仍然可供客户端使用。ping 测试通过向考虑中的网站发出请求并分析返回的响应状态代码来实现这一点
为什么并发适用于 web 请求?
向 web 服务器发出不同请求的过程以及解析和处理下载的 HTML 源代码的过程都是独立于不同请求的。
开发网页抓取应用时需要考虑哪些因素?
开发并发 web 请求的应用时,应考虑以下因素:
- 服务条款和数据收集政策
- 错误处理
- 定期更新你的程序
- 避免过度刮擦
什么是过程?进程和线程之间的核心区别是什么?
进程是由操作系统执行的特定计算机程序或软件的实例。流程包含程序代码及其当前活动以及与其他实体的交互。同一进程中可以实现多个线程来访问和共享内存或其他资源,而不同的进程不会以这种方式交互。
什么是多重处理?多处理和多线程之间的核心区别是什么?
多处理是指从操作系统执行多个并发进程,其中每个进程在单独的 CPU 上执行,而不是在任何给定时间执行单个进程。另一方面,多线程是在同一进程中执行多个线程。
多处理模块提供哪些 API 选项?
multiprocessing模块向Process类提供 API,该类包含流程的实现,同时提供使用类似于threading模块的 API 生成流程并与流程交互的方法。该模块还提供了Pool类,主要用于实现一个进程池,每个进程将执行提交的任务。
多处理模块中Process类与Pool类的核心区别是什么?
Pool类实现了一个进程池,每个进程都将执行提交给Pool对象的任务。一般来说,Pool类比Process类更方便,尤其是当并发应用返回的结果需要排序时。
确定 Python 程序中当前进程的选项有哪些?
multiprocessing模块提供current_process()方法,返回当前在程序任意点运行的Process对象。另一种跟踪程序中运行进程的方法是通过os模块查看各个进程 ID。
什么是守护进程?在多处理程序中等待进程的目的是什么?
守护进程在后台运行,不会阻止主程序退出。当主程序无法轻松判断在任何给定时间中断进程是否合适时,或者在未完成辅助程序的情况下退出主程序不影响最终结果时,此规范很常见。
如何终止流程?为什么有时可以接受终止进程?
multiprocessing.Process类中的terminate()方法提供了一种快速终止进程的方法。如果程序中的进程从未与共享资源交互,terminate()方法非常有用,尤其是当进程看起来没有响应或死锁时。
Python 中促进进程间通信的方法有哪些?
虽然锁是线程间通信最常用的同步原语之一,但管道和队列是不同进程间通信的主要方式。具体地说,它们提供了消息传递选项以促进进程之间的通信:用于两个进程之间连接的管道,以及用于多个生产者和消费者的队列。
什么是还原运算符?必须满足哪些条件才能使一个算子成为约化算子?
如果运算符满足以下条件,则为约化运算符:
- 运算符可以将元素数组缩减为一个标量值
- 最终结果(标量值)是通过创建和计算部分任务获得的
还原运算符具有哪些与所需条件等效的属性?
交际性和联想性被认为等同于约化算子的要求。
归约运算符和并发编程之间有什么联系?
归约运算符要求具有交际和联想属性。因此,它们的子任务必须能够独立处理,这使得并发性和并行性适用。
在使用多处理程序时,必须考虑哪些因素,以促进 Python 中的进程间通信?
一些注意事项包括实现毒丸技术,以便子任务分布在所有消费者流程中;每次调用get()函数时,在任务队列上调用task_done(),以确保join()函数不会无限期阻塞;避免使用不可靠且未在 Unix 操作系统上实现的qsize()方法。
并发归约算子的一些实际应用是什么?
一些实际应用包括大量的数字运算运算符和利用逻辑运算符的复杂程序。
什么是图像处理任务?
图像处理的任务是分析和处理数字图像文件,以创建图像的新版本,或从中提取重要数据。
数字成像的最小单位是什么?它是如何在计算机中表现出来的?
数字成像的最小单位是一个像素,它通常包含一个 RGB 值:一个介于 0 和 255 之间的整数元组。
什么是灰度缩放?这项技术有什么用途?
灰度缩放是通过仅考虑由可用光量表示的每个像素的强度信息,将图像转换为灰色的过程。它通过将传统的三维彩色数据映射到一维灰度数据来降低图像像素矩阵的维数。
什么是阈值?这项技术有什么用途?
如果像素的强度大于先前指定的阈值,则阈值化将图像中的每个像素替换为白色像素,如果像素的强度小于该阈值,则阈值化将替换为黑色像素。在对图像执行阈值处理后,该图像的每个像素只能保持两个可能的值,从而显著降低了图像数据的复杂性。
为什么图像处理要同时进行?
当涉及到图像处理时,通常会涉及大量的计算数字处理过程,因为每个图像都是整数元组矩阵。然而,这些过程可以独立执行,这意味着整个任务应该是并发的。
并行图像处理有哪些好的做法?
并发图像处理的一些良好实践如下:
- 选择正确的方法(从众多方法中选择)
- 生成适当数量的进程
- 同时处理输入/输出
异步编程背后的思想是什么?
异步编程是一种编程模型,它侧重于协调应用中的不同任务,目标是应用将使用最少的时间来完成这些任务。同步程序在适当的情况下从一个任务切换到另一个任务,以在等待的任务之间创建重叠和处理时间,从而缩短完成整个程序所需的总时间。
异步编程与同步编程有何不同?
在同步编程中,程序的指令按顺序执行:一个任务必须在程序中的下一个任务开始处理之前完成执行。对于异步编程,如果当前任务需要花费大量时间才能完成,则可以选择在任务期间的某个时间指定将执行切换到另一个任务。
异步编程与线程和多处理有何不同?
异步编程将程序的所有指令保持在同一线程和进程中。异步编程背后的主要思想是,如果在处理第二个任务的同时简单地等待第一个任务一段时间更有效(就执行时间而言),那么就让一个执行器从一个任务切换到另一个任务
什么是异步编程?它有什么优势?
异步编程是一种编程模型,它利用协调计算任务来重叠等待和处理时间。如果成功实现,与同步编程相比,异步编程既能提供响应能力,又能提高速度。
异步程序中的主要元素是什么?它们如何相互作用?
异步程序有三个主要组件:事件循环、协程和未来。事件循环负责使用其任务队列调度和管理协同路由;协同路由是异步执行的计算任务,每个协同路由必须在其函数中指定将执行流返回到事件循环(即任务切换事件)的确切位置;未来是占位符对象,包含从协同路由获得的结果。
什么是async和await关键词?它们有什么用途?
async和await关键字由 Python 语言提供,作为在低级别实现异步编程的一种方式。async关键字放在函数前面,以将其声明为协同程序,而await关键字指定任务切换事件。
在异步编程的实现方面asyncio模块提供了哪些选项?
asyncio模块提供易于使用的 API 和直观的框架来实现异步程序;此外,该框架使异步代码与同步代码一样可读,这在异步编程中通常非常罕见。
Python 3.7 在异步编程方面有哪些改进?
Python3.7 对 API 进行了改进,该 API 启动并运行异步程序的主事件循环,同时保留了async和await作为官方 Python 关键字。
什么是阻塞功能?为什么它们会给传统的异步编程带来问题?
阻塞函数具有不停止的执行,因此,它们阻止在异步程序中协作切换任务的任何尝试。如果强制将执行流释放回事件循环,阻塞函数将停止执行,直到轮到它们再次运行为止。在这种情况下,异步编程虽然仍能实现更好的响应,但无法提高程序的速度;事实上,由于各种开销,异步版本的程序在大多数情况下比同步版本需要更长的时间来完成执行。
concurrent.futures如何为异步编程提供阻塞函数的解决方案?它提供了哪些选择?
**concurrent.futures模块在异步程序中执行协程,实现线程化和多处理。它分别为独立线程和独立进程中的异步编程提供了ThreadPoolExecutor和ProcessPoolExecutor。
什么是沟通渠道?它与异步编程有什么联系?
通信信道用于表示不同系统之间的物理布线连接和便于计算机网络的数据逻辑通信。后者与计算有关,与异步编程的思想更为相关。异步编程可以提供功能,补充有效简化通信通道的过程。
开放系统互连(OSI)模型协议层的两个主要部分是什么?它们各自有什么用途?
媒体层包含与通信通道的底层进程交互的相当低级的操作,而主机层处理高级数据通信和操作。
什么是传输层?为什么它对沟通渠道至关重要?
传输层通常被视为媒体层和主机层之间的概念过渡,负责沿不同系统之间的端到端连接发送数据。
asyncio如何促进服务器端通信通道的实现?
**就服务器而言,asyncio模块将传输的抽象与异步程序的实现结合起来。具体而言,asyncio通过其BaseTransport和BaseProtocol类提供了不同的方式来定制通信信道的底层架构。
asyncio如何促进客户端通信渠道的实施?
**与aiohttp模块,特别是aiohttp.ClientSession一起,asyncio还通过异步发出请求和读取返回的响应,提供了客户端通信过程的效率和灵活性。
什么是aiofiles?
aiofiles模块可以与asyncio和aiohttp协同工作,有助于异步文件读写。
什么会导致死锁,为什么会不受欢迎?
不同锁对象之间缺乏协调(或处理不当)可能会导致死锁,在这种情况下无法取得任何进展,并且程序被锁定在其当前状态。
哲学家进餐问题与死锁问题有何关联?
在哲学家进餐问题中,由于每个哲学家的左手只拿着一把叉子,他们无法继续吃饭或放下手中的叉子。哲学家吃食物的唯一方式是让他们的邻居哲学家放下叉子,这只有在他们能吃自己的食物时才可能;这创造了一个永远无法满足的条件循环。从本质上说,这种情况是死锁的性质,在这种情况下,一个系统的所有要素都原地踏步,无法取得任何进展。
科夫曼的四个条件是什么?
死锁也由并发程序同时需要具备的必要条件来定义,以使死锁发生。这些条件最初是由计算机科学家小爱德华·G·科夫曼提出的,因此被称为科夫曼条件。条件如下:
-
至少有一个资源必须处于不可共享状态。这意味着该资源由单个进程(或线程)持有,其他进程无法访问该资源;在任何给定时间,资源只能由单个进程(或线程)访问和持有。这种情况也称为互斥。
-
存在一个进程(或线程),该进程(或线程)同时访问一个资源并等待其他进程(或线程)持有的另一个资源。换句话说,这个进程(或线程)需要访问两个资源才能执行它的指令,一个指令已经被它持有,另一个指令正在等待来自其他进程(或线程)的指令。这种情况称为等待。
-
资源只能由持有资源的进程(或线程)释放,前提是该进程(或线程)有特定的指令可以这样做。也就是说,除非进程(或线程)主动释放资源,否则该资源将保持不可共享状态。这是无抢占条件。
-
最终条件称为循环等待。如名称所示,此条件指定存在一组进程(或线程),使得集合中的第一个进程(或线程)处于等待状态,等待第二个进程(或线程)释放资源,而第二个进程(或线程)需要等待第三个进程(或线程);最后,集合中的最后一个进程(或线程)正在等待第一个进程。
资源排名如何解决死锁问题?在实施时还会出现哪些其他问题?
如果进程(或线程)要以预定的静态顺序访问资源,则它们获取和等待资源的方式的循环性质将被消除,而不是随意访问资源。但是,如果您对并发程序的资源设置了足够的锁,那么它的执行将完全是顺序的,再加上并发编程功能的开销,它的速度将比程序的纯顺序版本更慢。
忽略锁如何解决死锁问题?在实施时,还会出现哪些其他问题?
通过忽略锁,我们的程序资源可以在并发程序中的不同进程/线程之间有效地共享,从而消除了四个 Coffman 条件中的第一个条件互斥。然而,这样做可以被视为完全误解了问题。我们知道锁的使用是为了使进程和线程能够以系统、协调的方式访问程序中的共享资源,以避免错误处理数据。删除并发程序中的任何锁定机制意味着共享资源(现在不受访问限制)以不协调的方式被操纵(因此被破坏)的可能性显著增加。
livelock 与死锁有什么关系?
在活锁情况下,并发程序中的进程(或线程)能够切换它们的状态,但它们只是无限地来回切换,无法取得任何进展。
什么是饥饿,为什么它在并发程序中是不受欢迎的?
饥饿是并发系统中的一个问题,在并发系统中,进程(或线程)无法访问继续执行所需的资源,因此无法取得任何进展。
饥饿的根本原因是什么?饥饿的常见表面原因是什么,可以从根本原因表现出来?
大多数情况下,调度指令的协调性差是导致饥饿的主要原因。饥饿的一些高级原因可能包括:
- 具有高优先级的进程(或线程)控制着 CPU 中的执行流,因此,低优先级的进程(或线程)没有机会执行它们自己的指令。
- 高优先级的进程(或线程)支配着不可共享资源的使用,因此,低优先级的进程(或线程)没有机会执行它们自己的指令。这种情况与第一种情况类似,但涉及访问资源的优先级,而不是执行本身的优先级。
- 具有低优先级的进程(或线程)正在等待资源执行其指令,但一旦资源可用,具有较高优先级的其他进程(或线程)将立即被授予访问它们的权限,因此低优先级的进程(或线程)将无限期地等待。
死锁和饥饿之间有什么联系?
死锁情况也可能导致饥饿,因为饥饿的定义指出,如果存在一个进程(或线程)由于无法访问必要的进程而无法取得任何进展,则该进程(或线程)正在经历饥饿。哲学家进餐问题也说明了这一点。
读者和作者的问题是什么?
读写器问题需要一种调度算法,以便读写器能够正确有效地访问文本文件,而不会错误处理/损坏所包含的数据。
解决读者-作者问题的第一种方法是什么?为什么在这种情况下会出现饥饿?
第一种方法允许多个读卡器同时访问文本文件,因为读卡器只需读取文本文件,而不更改其中的数据。第一种方法的问题是,当读卡器正在访问文本文件,而写入器正在等待文件解锁时,如果另一个读卡器开始执行并希望访问该文件,则它将被赋予比已经等待的写入器更高的优先级。此外,如果越来越多的读卡器不断请求访问该文件,那么写卡器将无限期地等待。
解决读者-作者问题的第二种方法是什么?为什么在这种情况下会出现饥饿?
这种方法实现了一种规范,即一旦写入程序请求访问文件,就不应该有读卡器能够在该写入程序之前插队访问该文件。与我们在读卡器-写入程序问题的第一个解决方案中看到的不同,此解决方案优先考虑写入程序,因此,读者们饥肠辘辘。
解决读者-作者问题的第三种方法是什么?为什么它成功地解决了饥饿问题?
这种方法在读写器上都实现了锁定。然后,所有线程都将受制于锁的常量,因此在不同的线程之间将实现同等的优先级。
饥饿的常见解决方案是什么?
饥饿的一些常见解决方案包括:
- 增加低优先级线程的优先级
- 实现先进先出线程队列
- 一种优先级队列,它还为已在队列中等待很长时间的线程提供逐渐增加的优先级
- 或者,如果一个线程已经能够多次访问共享资源,那么它的优先级就会降低
什么是关键部分?
关键部分表示由并发应用中的多个进程或线程访问的共享资源,这可能导致意外甚至错误的行为。
什么是竞争条件,为什么它在并发程序中是不受欢迎的?
当两个或多个线程/进程同时访问和更改共享资源时,会发生争用情况,从而导致数据处理错误和损坏。
种族状况的根本原因是什么?
争用条件的根本原因是多个线程/进程同时读取和更改共享资源;并且,当所有线程/进程完成执行时,只注册最后一个线程/进程的结果。
锁如何解决竞争条件的问题?
由于多个线程或进程同时访问和写入共享资源时会出现争用情况,因此解决方案是隔离不同线程/进程的执行,特别是在与共享资源交互时。使用锁,我们可以将并发程序中的共享资源转换为关键部分,从而保证数据的完整性。
为什么并发程序中有时不需要锁?
使用锁有很多缺点:在一个并发程序中实现足够多的锁,整个程序可能会变得完全连续;锁不会锁任何东西。
现实生活中的系统和应用中,竞争条件会带来什么问题?
竞争条件在现实系统和应用中引起的问题如下:
-
安全:竞争条件既可以作为安全漏洞(让外部代理非法访问系统)加以利用,也可以作为安全过程的随机密钥生成。
-
操作系统:当两个代理(用户和应用)与同一内存空间交互时发生的竞争情况可能导致不可预测的行为。
-
联网:在联网中,一个竞争条件可能会导致在一个网络中给多个用户提供强大的权限。
Python 和 C++之间的内存管理有什么不同?
C++通过简单地将变量写入变量的内存位置,将变量与它的值关联起来;Python 的变量引用点指向它们所持有的值的内存位置。因此,Python 需要为其内存空间中的每个值维护一个引用计数。
GIL 为 Python 解决了什么问题?
为了避免竞争条件,从而避免值引用计数的损坏,实现了 GIL,以便在任何给定时间只有一个线程可以访问和修改计数。
GIL 给 Python 带来了什么问题?
GIL 有效地防止多个线程利用 CPU 并同时执行 CPU 绑定的指令。这意味着,如果要并发执行的多个线程是 CPU 绑定的,那么它们实际上将按顺序执行。
在 Python 程序中规避 GIL 的方法有哪些?
有几种方法可以处理 Python 应用中的 GIL;也就是说,实现多处理而不是多线程,并利用其他可选的 Python 解释器。
解决锁不能锁定任何东西的问题的主要方法是什么?
主要方法是在数据结构的类属性和方法中内部实现锁,以便外部函数和程序不能绕过这些锁并同时访问共享的并发对象。
描述并行编程环境下的可伸缩性概念。
所谓程序的可伸缩性,是指当程序要处理的任务量增加时,性能的变化。Andre B.Bondi 将术语可伸缩性定义为,“一个系统、网络或流程处理不断增长的工作量的能力,或其扩大以适应这种增长的潜力。”
简单的锁定机制如何影响并发程序的可伸缩性?
简单的基于锁的数据结构的可伸缩性是非常不受欢迎的:随着向程序中添加更多线程以执行更多任务,程序的性能会线性下降。由于在任何给定时间只有一个线程可以访问并递增共享计数器,因此程序必须执行的递增次数越多,完成所有递增的任务所需的时间就越长。
什么是近似计数器,它们如何帮助解决并发编程中的可伸缩性问题?
近似计数器背后的基本思想是在其他低级计数器之间分配工作(增加共享全局计数器)。当活动线程执行并希望增加全局计数器时;首先,它必须增加其相应的本地计数器。每个线程有一个单独的计数器对象,线程可以独立地同时更新其相应的本地计数器,从而创建重叠,从而提高程序的速度性能。
Python 中是否可以使用无锁数据结构?为什么,或者为什么不?
由于**全局解释器锁****【GIL】**的存在,使得无锁的特性无法在 CPython 中实现,这会阻止在任何给定时间在 CPU 中执行多个线程。
什么是无互斥的并发数据结构,它与基于并发锁的数据结构有何不同?
术语“无互斥体的并发数据结构”表示缺少锁定机制以及使用其他同步机制来保护数据。
什么是 RCU 技术,对于无互斥的并发数据结构,它解决了什么问题?
为了保护并发数据结构的完整性,当线程或进程请求对其进行读写访问时,RCU 技术会创建并维护另一版本的数据结构。通过在一个单独的副本中隔离数据结构和线程/进程之间的交互,RCU 确保不会发生冲突数据。
Python 内存管理器的主要组件是什么?
Python 内存管理器的主要组件如下:
- 原始内存分配器通过与操作系统的内存管理器交互,在较低级别处理内存分配。
- 特定于对象的内存分配器与 Python 中对象和值的私有堆进行交互。这些分配器执行特定于给定数据和对象类型的内存操作。
- 标准 C 库中的系统分配器负责帮助原始内存分配器与操作系统的内存管理器交互。
Python 内存模型与带标签的有向图有何相似之处?
内存模型只通过指针跟踪其数据和变量:每个变量的值都是指针,该点可以指向符号、数字或子例程。因此,这些指针是对象图中的有向边,实际值(符号、数字和子例程)是图中的节点。
在用 Python 开发并发应用方面,Python 内存模型的优点和缺点是什么?
对并发程序的行为进行推理要比在另一种编程语言中进行推理容易得多。然而,在 Python 中理解和调试并发程序的容易性也伴随着性能的降低。
什么是原子操作,为什么在并发编程中需要原子操作?
原子操作是在执行过程中不能中断的指令。原子性是并发操作的理想特性,因为它保证了跨不同线程共享的数据的安全性。
给出 Python 中固有的原子操作的三个示例。
一些例子如下:
- 将预定义对象追加到列表
- 用另一个列表扩展列表
- 从列表中提取元素
- 从列表中弹出
- 排序列表
- 将一个变量赋给另一个变量
- 将变量指定给对象的属性
- 为字典创建新条目
- 使用其他词典更新词典
什么是插座?它与网络编程有什么关系?
低级网络编程通常涉及套接字的操作和处理,套接字被定义为特定计算机网络节点内的理论端点,负责接收或发送来自其所在节点的数据。
当潜在客户请求连接时,服务器端通信的过程是什么?
要从服务器端打开通信通道,网络程序员必须首先创建套接字并将其绑定到特定地址。然后,服务器开始侦听网络中客户端创建的任何潜在通信请求。在收到来自潜在客户机的连接请求后,服务器现在可以决定是否接受该请求。然后在网络中的两个系统之间建立连接,这意味着它们可以开始相互通信和共享数据。当客户端通过通信信道向服务器发送消息时,服务器随后处理该消息,并最终通过相同信道向客户端发送响应;这一过程一直持续到它们之间的连接结束,要么通过其中一个退出连接通道,要么通过一些外部因素。
socket 模块提供了哪些方法来帮助服务器端的底层网络编程?
以下是一些重要的方法:
socket.bind()将调用套接字绑定到传递给方法的地址socket.listen()允许我们创建的服务器接受来自潜在客户端的连接socket.accept()接受调用套接字对象具有的特定连接socket.makefile()返回与调用套接字对象关联的文件对象socket.sendall()将作为参数传递的数据发送给调用套接字对象socket.close()将调用套接字对象标记为关闭
什么是发电机?与 Python 列表相比,它们的优势是什么?
生成器是返回迭代器的函数,可以动态暂停和恢复。生成器迭代器是惰性的,只有在特别要求时才会生成结果。由于这个原因,生成器迭代器在内存管理方面更有效,因此在涉及大量数据时,它通常优于列表。
什么是异步发电机?如何应用它们来构建非阻塞服务器?
异步生成器允许执行流在生成任务之间切换。结合使用可在以后运行的回调,服务器可以同时读取和处理来自多个客户端的数据。
什么是调度程序?为什么它不是一个调度服务?
APScheduler 是一个外部 Python 库,支持调度稍后执行的 Python 代码。APScheduler 本身不是一个具有内置 GUI 或命令行界面的调度服务。它仍然是一个 Python 库,必须在现有应用中导入和使用。但是,APScheduler 具有许多功能,可以利用这些功能来构建实际的调度服务。
APScheduler 的主要调度功能是什么?
它提供了三种不同的调度机制:cron 风格的调度、基于间隔的执行和延迟执行。此外,APScheduler 允许存储要在各种后端系统中执行的作业,并使用常见的 Python 并发框架,如 AsyncIO、Gevent、Tornado 和 Twisted。最后,APScheduler 通过指定适当的执行者,提供了不同的选项来实际执行计划代码。
ApsScheduler 和 Python 中的另一个调度工具芹菜有什么区别?
芹菜是一种具有基本调度功能的分布式任务队列,而 APScheduler 则恰恰相反:它是一种具有基本任务队列选项和高级调度功能的调度器。用户报告说,APScheduler 比芹菜更容易设置和实现。
编程测试的目的是什么?在并发编程中有什么不同?
测试会引发错误,表明程序中存在 bug。测试并发程序通常很困难,因为非确定性允许在一次测试中检测到并发错误,而在另一次测试中则不可见。我们称这些并发性错误为不可复制的,它们可能在不同的测试中变得不可见,这就是为什么我们不能在测试中做出响应以一致地检测所有并发性错误的主要原因。
本章讨论的测试方法是什么?
单元测试适用于所考虑的程序的各个单元,其中单元是程序中最小的可测试部分。另一方面,静态代码分析在不执行它的情况下查看实际代码本身。静态代码分析扫描代码结构中的可视错误以及变量和函数的使用。
编程调试的目的是什么?在并发编程中有什么不同?
调试是程序员试图识别和解决问题或缺陷的过程,这些问题或缺陷会导致他们所在的计算机应用产生不正确的结果,甚至停止运行。与测试并发程序的问题类似,调试在应用于并发时,由于共享资源可以同时与多个代理交互(并被多个代理更改),因此可能变得越来越复杂和困难。
本章讨论的调试方法是什么?
常规调试方法包括打印调试、日志记录、跟踪和使用调试器。调试并发程序的过程可以利用最小化、单线程/处理和操纵调度来放大潜在的 bug。********
