Fluent Python2 【Chapter21_QA】
1. python信号量的概念的理解
在Python中,信号量(Semaphore)是一种用于控制对共享资源的访问的同步机制。它可以确保在任何给定时间内,只有一定数量的线程或进程可以访问特定的资源。
信号量的概念和用途类似于现实生活中的一些场景,下面我将通过一个通俗的例子来解释信号量。
假设有一个停车场,总共只有5个停车位。如果有多辆车同时到达并想要停车,就需要一种机制来控制汽车的进入。这时,我们可以使用一个信号量来管理停车位的使用情况。
最初,我们创建一个信号量,它的值被设置为5,表示有5个可用的停车位。每当一辆车进入停车场时,它必须先获取信号量(semaphore.acquire())。如果信号量的值大于0,表示还有可用的停车位,汽车就可以进入停车场,同时信号量的值减1。如果信号量的值为0,表示所有停车位都被占用,那么汽车就必须等待,直到有其他车辆离开停车场,释放一个停车位(semaphore.release())。
下面是一个Python代码示例,演示了如何使用信号量来控制对共享资源的访问:
import threading import time # 创建一个信号量,初始值为5 semaphore = threading.Semaphore(5) def car(id): # 车辆请求进入停车场 semaphore.acquire() print(f"Car {id} entered the parking lot.") # 模拟停车时间 time.sleep(2) # 车辆离开停车场,释放一个停车位 print(f"Car {id} left the parking lot.") semaphore.release() # 创建10辆车,模拟它们进入停车场 for i in range(10): t = threading.Thread(target=car, args=(i,)) t.start()
2. from path import Path, Path的含义、作用l理解
from path import Path 这一行代码是从一个名为 path 的包中导入了 Path 类或模块。Path 在 Python 中用于表示文件系统路径,使得操作文件和目录变得更加方便和面向对象。
Path 的作用主要有以下几点:
- 跨平台:无需考虑不同操作系统中路径分隔符(Windows 使用
\、UNIX 使用/)的差异。 - 面向对象:可以将路径视为对象,使用对象方法来操作路径,更直观和易于理解。
- 方便操作:提供了丰富的方法来检查路径是否存在、读写文件、遍历目录等操作。
- 字符串表示:可以使用字符串或字节序列来表示一个路径对象。
举个通俗易懂的例子:
假设你想在当前目录下创建一个名为 data 的文件夹,并在其中创建一个名为 info.txt 的文本文件,最后向文件写入一些内容。使用传统方式,你需要这样做:
import os # 创建目录 os.mkdir('data') # 打开文件并写入内容 with open(os.path.join('data', 'info.txt'), 'w') as f: f.write('Hello, World!')
使用 Path 对象,可以这样实现:
from pathlib import Path # 创建目录 data_dir = Path.cwd() / 'data' data_dir.mkdir(exist_ok=True) # 创建并写入文件 info_file = data_dir / 'info.txt' info_file.write_text('Hello, World!')
可以看到,使用 Path 对象操作路径更加直观和简洁。你无需手动拼接路径字符串,也不需要考虑不同系统的路径分隔符问题。
总的来说,Path 对象提供了一种高级和面向对象的方式来处理文件系统路径,使得路径操作变得更加 Pythonic,可读性和可维护性也得到了提高。当你需要频繁操作文件和目录时,使用 Path 会带来很大便利。
3. 9. 一个通俗易懂经典例子和衍生的同步、异步代码对比。


如下是案例。
多去执行下,感受下过程,增强对异步的理解。
############################################################## # Example-1 顺序执行 总共30s ############################################################## from time import sleep def hello(): print('Hello') sleep(3) print('World') if __name__ == '__main__': print(f'started at {time.strftime("%X")}') for i in range(10): hello() print(f'finished at {time.strftime("%X")}')
############################################################### # Example-2 异步执行 总共3s ############################################################### import asyncio import time # loop = asyncio.get_event_loop() async def hello(): print('Hello') await asyncio.sleep(3) print('World') async def main(): tasks = [asyncio.create_task(hello()) for _ in range(10)] await asyncio.gather(*tasks) if __name__ == '__main__': print(f'started at {time.strftime("%X")}') asyncio.run(main()) print(f'finished at {time.strftime("%X")}')
############################################################### # Example-3 异步执行 总共耗时3s ############################################################### import gevent from gevent import sleep def hello(): print('Hello') sleep(3) print('World') if __name__ == '__main__': print(f'started at {time.strftime("%X")}') jobs = [gevent.spawn(hello) for i in range(10)] gevent.wait(jobs) print(f'finished at {time.strftime("%X")}')
############################################################### # Example-4 异步执行 总共耗时3s ############################################################### import eventlet from eventlet import sleep, GreenPool def hello(): print('Hello') sleep(3) print('World') def main(): pool = GreenPool() jobs = [pool.spawn(hello) for _ in range(10)] pool.waitall() if __name__ == '__main__': import time print(f'started at {time.strftime("%X")}') main() print(f'finished at {time.strftime("%X")}')
参考经典讲解:
[1] https://www.youtube.com/watch?v=iG6fr81xHKA
[2] https://gist.github.com/miguelgrinberg/f15bc03471f610cfebeba62438435508
3. 进程、线程、协程对比

参考经典讲解:
[1] https://www.youtube.com/watch?v=iG6fr81xHKA
4. 如何理解Scalability
在计算机科学和软件工程中,可扩展性(Scalability)是一个重要的概念,它指的是一个系统或应用在面临增加的工作量或用户数量时,能够有效地扩展以处理额外负载的能力。
专业解释
可扩展性通常分为三类:
-
垂直可扩展性(Vertical Scalability):通过增加单个计算机资源(如CPU、内存、存储或网络带宽)来提高系统性能。这通常涉及到升级硬件,如增加RAM或使用更快的处理器。
-
水平可扩展性(Horizontal Scalability):通过增加更多计算机(或服务器)来提高系统性能。这通常涉及到将工作负载分布到多个服务器上,以便可以并行处理更多任务。
-
架构可扩展性:指系统设计时考虑到的扩展性,包括使用设计模式、组件解耦、数据分片、分布式计算等技术,以便于在需要时能够轻松地增加资源或服务器。
通俗解释
想象一下,你正在举办一个大型聚会。随着参加人数的增加,你需要更多的座位、更大的食物供应和更多的饮料。这就是可扩展性的概念。
- 垂直可扩展性 就像是你增加了更多的桌子、椅子、食物和饮料,这样每个人都可以有足够的空间和食物。
- 水平可扩展性 就像是你租用了更多的场地,增加了更多的服务员和更多的食物供应,这样你可以容纳更多的人,而不会让每个人感到拥挤或饿着。
- 架构可扩展性 就像是你提前考虑到了可能会有更多的人参加,所以你设计了可以很容易地增加更多场地、服务员和食物供应的系统。
举例说明
-
垂直可扩展性:一个简单的例子是一个在线商店。如果访问量增加,你可以增加服务器的RAM和CPU,以处理更多的并发用户和订单。
-
水平可扩展性:一个社交媒体平台,随着用户数量的增加,你可以增加更多的服务器来处理用户生成内容、评论和帖子。
-
架构可扩展性:一个云计算服务,如AWS或Azure,允许你根据需要添加或减少计算资源,而无需担心底层的物理硬件。这使得服务能够轻松地扩展以满足不断变化的需求。
5. from enum import Enum, Enum的API理解
在Python中,Enum 是 enum 模块提供的一个类,用于定义枚举类型。枚举是一种特殊的数据类型,它由一组固定的值组成,这些值在定义时被赋予一个名称,通常用于表示状态、模式、选项等。
Enum的API
-
定义枚举:
from enum import Enum DownloadStatus = Enum('DownloadStatus', 'OK NOT_FOUND ERROR')
-
在这个例子中,我们导入了
Enum类,并定义了一个名为DownloadStatus的枚举。枚举的名称是可选的,如果不提供名称,默认使用类名。枚举的值由逗号分隔的字符串列表指定,这些值在定义时被赋予一个名称。 -
枚举成员: 一旦定义了一个枚举,就可以通过点(
.)运算符来访问枚举的成员。例如,DownloadStatus.OK、DownloadStatus.NOT_FOUND和DownloadStatus.ERROR都是DownloadStatus枚举的成员。 -
枚举成员的属性: 枚举成员可以具有属性,这些属性在枚举定义时通过等号(
=)指定。例如:
from enum import Enum DownloadStatus = Enum('DownloadStatus', 'OK NOT_FOUND=404 ERROR')
在这个例子中,DownloadStatus.NOT_FOUND 被赋予了属性 404,表示一个HTTP状态码。
4. 枚举成员的命名空间: 枚举成员可以访问其命名空间中的其他枚举成员。例如:
from enum import Enum DownloadStatus = Enum('DownloadStatus', 'OK NOT_FOUND ERROR') class HttpStatus(Enum): OK = 200 NOT_FOUND = 404 BAD_REQUEST = 400 DownloadStatus.OK.HttpStatus.OK # 返回 DownloadStatus.OK 的值,200
-
在这个例子中,
DownloadStatus.OK可以访问HttpStatus枚举中的成员。 -
枚举的枚举属性: 枚举可以具有枚举属性,这些属性在枚举定义时通过等号(
=)指定。例如:
from enum import Enum DownloadStatus = Enum('DownloadStatus', 'OK NOT_FOUND ERROR', start=1)
-
在这个例子中,
start=1指定枚举的起始值,后续的枚举值会从1开始。 -
枚举的枚举方法: 枚举可以定义自己的方法,这些方法可以通过点(
.)运算符访问。例如:
from enum import Enum DownloadStatus = Enum('DownloadStatus', 'OK NOT_FOUND ERROR', start=1) def print_status(self): print(f"{self.name} - {self.value}") DownloadStatus.add_method(print_status) DownloadStatus.OK.print_status() # 返回 OK - 1
-
在这个例子中,我们定义了一个名为
print_status的方法,并使用add_method方法将其添加到枚举中。 -
枚举的枚举属性: 枚举可以具有枚举属性,这些属性在枚举定义时通过等号(
=)指定。例如:
from enum import Enum DownloadStatus = Enum('DownloadStatus', 'OK NOT_FOUND ERROR', start=1) def print_status(self): print(f"{self.name} - {self.value}") DownloadStatus.add_method(print_status) DownloadStatus.OK.print_status() # 返回 OK - 1
在这个例子中,我们定义了一个名为 print_status 的方法,并使用 add_method 方法将其添加到枚举中。
6. 如下expand_cc_args函数中,else部分的理解。 [from flags2_common.py]
from pathlib import Path COUNTRY_CODES_FILE = Path('country_codes.txt') def expand_cc_args(every_cc: bool, all_cc: bool, cc_args: list[str], limit: int) -> list[str]: codes: set[str] = set() A_Z = string.ascii_uppercase if every_cc: codes.update(a + b for a in A_Z for b in A_Z) elif all_cc: text = COUNTRY_CODES_FILE.read_text() codes.update(text.split()) else: for cc in (c.upper() for c in cc_args): if len(cc) == 1 and cc in A_Z: codes.update(cc + c for c in A_Z) elif len(cc) == 2 and all(c in A_Z for c in cc): codes.add(cc) else: raise ValueError('*** Usage error: each CC argument ' 'must be A to Z or AA to ZZ.') return sorted(codes)[:limit] # Test Cases #体会下如下不同的测试用例,就很容易懂了 print(expand_cc_args(False, False, ['A'], 100)) # ['AA', 'AB', 'AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AI', 'AJ', 'AK', 'AL', 'AM', 'AN', 'AO', 'AP', 'AQ', 'AR', 'AS', 'AT', 'AU', 'AV', 'AW', 'AX', 'AY', 'AZ'] print(expand_cc_args(False, False, ['AA', 'AB', 'AC'], 10)) # ['AA', 'AB', 'AC'] print(expand_cc_args(False, False, ['AAA', 'AAB', 'AAC'], 10)) Traceback (most recent call last): File "D:\FluentPython2\test.py", line 3765, in <module> print(expand_cc_args(False, False, ['AAA', 'AAB', 'AAC'], 10)) File "D:\FluentPython2\test.py", line 3758, in expand_cc_args raise ValueError('*** Usage error: each CC argument ' ValueError: *** Usage error: each CC argument must be A to Z or AA to ZZ.
7. 如何理解add_argument()函数的常见参数含义和用法
官方文档API:argparse — Parser for command-line options, arguments and sub-commands
这里先提到:metavar, nargs, action='store_true'
3. 如何理解如下代码的AsyncClient这个类
4. asyncio.to_thread()函数该如何理解?
5. asyncio背后调用的run_in_executor是干啥的?该如何理解
6. 倒排索引是什么?有什么作用?
7. L1缓存、L2缓存、L3缓存的含义分别是什么?
8. 结构化并发的概念理解。Curio框架

浙公网安备 33010602011771号