Skip to content

Commit d76662f

Browse files
📝 删除并发与并行文档,优化文档结构
- 删除了关于并发与并行的文档,简化了文档内容。 - 该文档包含的多进程、多线程和协程的相关信息已整合至其他部分,确保信息的连贯性和实用性。
1 parent 23a96bd commit d76662f

File tree

8 files changed

+469
-421
lines changed

8 files changed

+469
-421
lines changed

docs/docs/选择编程语言/Python/Python模块库/并发与并行.mdx

Lines changed: 0 additions & 421 deletions
This file was deleted.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
---
2+
sidebar_position: 3
3+
title: asyncio
4+
---
5+
### asyncio 模块
6+
7+
协程是编写并发代码的库,是构建 IO 密集型和高级结构化网络代码的最佳选择。
8+
9+
例程的运行方式是通过代码主动切换状态并等待处理,因此效率更高,语法也更详细。循环对象需要处于活动状态:创建、设置、提交、等待运行和停止。
10+
11+
例行程序的最佳数量取决于内存使用情况。
12+
13+
asyncio 模块包含了一些工具,用于编写异步代码。
14+
15+
协程的工作原理是事件循环,事件循环是一个无限循环,它等待事件并执行它们。
16+
17+
每次任务会被挂起至事件循环队列中,然后按顺序执行。
18+
19+
await 关键字用于挂起协程,直到它被调用。
20+
21+
async 关键字用于定义协程。
22+
23+
asyncio 模块用于实现异步编程。
24+
25+
[asyncio](https://docs.python.org/zh-cn/3.10/library/asyncio.html?highlight=asyncio#module-asyncio):asyncio Multiprocessing Module Code Documentation
26+
27+
```python showLineNumbers
28+
import asyncio
29+
30+
class TestA:
31+
def __init__(self,loop) -> None:
32+
self.loop = loop
33+
asyncio.set_event_loop(loop=self.loop) # step 3.1
34+
35+
async def run_page(self,tid): # step 7
36+
print(tid)
37+
# 此处编写爬虫代码
38+
return tid
39+
40+
async def close(self,):
41+
for i in asyncio.all_tasks(): # step 9.1
42+
i.cancel()
43+
self.loop.stop() # step 9.2
44+
45+
46+
def test():
47+
get_async_loop = asyncio.new_event_loop() # step 1
48+
asyncio.set_event_loop(get_async_loop) # step 2
49+
50+
async def spider(task_obj):
51+
async_task = [asyncio.ensure_future(task_obj.run_page(1)),
52+
asyncio.ensure_future(task_obj.run_page(2)),] # step 6
53+
await asyncio.wait(async_task) # step 8
54+
55+
await task_obj.close() # step 9
56+
57+
task_obj = TestA(get_async_loop) #step 3
58+
asyncio.run_coroutine_threadsafe(spider(task_obj), loop=get_async_loop) #step 4
59+
get_async_loop.run_forever() # step 5
60+
61+
test()
62+
```
63+
64+
生成器函数与协程(注:函数)非常相似,它们 yield 多次,它们具有多个入口点,并且它们的执行可以被挂起。唯一的区别是生成器函数不能控制在它在 yield 后交给哪里继续执行,控制权总是转移到生成器的调用者
65+
66+
在 Python 创建协程时,task 是 future 的子类,所以 task 继承了 future 的属性和方法。几乎没有不同。
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
sidebar_position: 5
3+
title: concurrent
4+
---
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
sidebar_position: 1
3+
title: 并发与并行
4+
---
5+
6+
进程:操作系统分配资源的基本单位。多进程属于并行:在同一时刻同时处理多个任务。
7+
8+
线程:操作系统调度资源的最小单位。多线程属于并发:在一段时间内交替处理多个任务。
9+
10+
协程:你可以把它想象成在一个线程内部,多个任务之间进行协作和切换。协程属于并发:在一段时间内交替处理多个任务。
11+
12+
:::tip
13+
多进程、多线程的出现,核心目的是为了最大限度地利用中央处理器(CPU)这一关键硬件资源。
14+
15+
多进程通过调动更多的CPU核心,从而提高程序的执行效率。
16+
17+
那为什么多线程没有使用更多的资源,只是交替处理多个任务,就能更快?
18+
19+
以一个常见的爬虫任务为例,其工作流程可以分为两个主要步骤:
20+
1. CPU指挥网卡发送网络请求,这一过程往往需要等待远程服务器响应(例如,网络通信耗时1秒)。
21+
2. CPU指挥磁盘将接收到的数据写入磁盘,完成持久化存储(例如,磁盘耗时19秒)。
22+
23+
24+
* **单线程模式**:在单线程下处理10个网址,程序必须顺序执行。当第一个网址的网络请求发送后,程序会进入**等待状态**,直到数据完全写入磁盘(总耗时20秒)后,才能开始处理第二个网址。因此,处理10个网址的总耗时将是 $10 \times 20$ 秒,即200秒。CPU长时间闲置。
25+
26+
* **多线程模式**:多线程则能显著提高效率。当第一个线程发出网络请求后,CPU不再闲置等待,而是立即切换到第二个线程,发起新的网络请求。这样,CPU可以**在等待I/O操作(如网络响应和磁盘写入)完成的同时,处理其他任务**。通过这种方式,CPU最大程度不空闲,指挥多个网络请求和磁盘写入操作**并行进行**,从而大幅缩短总体的完成时间。
27+
28+
这个切换过程称之为**上下文切换**,会产生一定的开销,由操作系统自动完成,操作系统不一定在最合理的时间点进行上下文切换。
29+
30+
因此为了进一步提高效率,我们使用协程来完成这个任务。在协程中,程序员在代码中编写`await`关键字来完成主动**上下文切换**
31+
:::
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
---
2+
sidebar_position: 1
3+
title: multiprocessing
4+
---
5+
### multiprocessing 模块
6+
7+
进程是系统独立安排和分配系统资源(CPU、内存)的基本单位,操作系统以进程为单位分配存储空间,操作系统管理所有进程的执行,为它们合理的分配资源。
8+
9+
一个进程就是 macOS 中的“活动监视器”、Windows 中的“任务管理器”的一个执行程序。
10+
11+
#### 多进程
12+
13+
进程之间是相互独立的,Python 中的进程通信一般由进程对 Queue 完成。
14+
15+
进程绕过了全局解释器锁。因此,多进程模块允许程序员充分利用特定机器上的多个处理器。它在 Unix 和 Windows 上都能运行。
16+
17+
进程的数量等于 CPU 核心的数量,这是最有效的。如果核数太多,就不能充分利用核数。如果太少,会造成进程切换,增加程序的运行时间。
18+
19+
[multiprocessing](https://docs.python.org/zh-cn/3.10/library/multiprocessing.html?highlight=multiprocessing#module-multiprocessing):Multiprocessing Module Code Documentation
20+
21+
```python showLineNumbers
22+
from multiprocessing import Pool
23+
24+
def f(vaule):
25+
x = vaule[0]
26+
y = vaule[1]
27+
return x*y
28+
29+
if __name__ == '__main__':
30+
p = Pool(16) # new 16 process pools , because i have 16 cpu
31+
print(p.map(f, [(1,1), (2,2), (3,3)])) # take in data
32+
p.close() # close pool
33+
34+
# [1, 4, 9]
35+
```
36+
37+
我们来完成 1~100000000 求和的计算密集型任务,循环解决,暂时也不考虑列表切片操作花费的时间,只是把做运算和合并运算结果的时间统计出来。
38+
39+
```python showLineNumbers
40+
from time import time
41+
42+
43+
def main():
44+
total = 0
45+
number_list = [x for x in range(1, 100000001)]
46+
start = time()
47+
for number in number_list:
48+
total += number
49+
print(total)
50+
end = time()
51+
print('Execution time: %.3fs' % (end - start))
52+
53+
```
54+
55+
```python showLineNumbers
56+
main()
57+
# 5000000050000000
58+
# Execution time: 6.798s
59+
```
60+
61+
利用多进程“分而治之”,
62+
63+
当我们将这个任务分解到 8 个进程中去执行:
64+
65+
```python showLineNumbers
66+
from multiprocessing import Process, Queue
67+
from time import time
68+
69+
core_num = 8
70+
71+
72+
def task_handler(curr_list, result_queue):
73+
total = 0
74+
for number in curr_list:
75+
total += number
76+
result_queue.put(total)
77+
78+
79+
def main():
80+
processes = []
81+
number_list = [x for x in range(1, 100000001)]
82+
result_queue = Queue()
83+
index = 0
84+
# 启动core_num(8)个进程将数据切片后进行运算
85+
index_batch = int(100000000 / core_num)
86+
for _ in range(core_num):
87+
p = Process(target=task_handler,
88+
args=(number_list[index:index + index_batch], result_queue))
89+
index += index_batch
90+
processes.append(p)
91+
p.start()
92+
# 开始记录所有进程执行完成花费的时间
93+
start = time()
94+
for p in processes:
95+
p.join()
96+
# 合并执行结果
97+
total = 0
98+
while not result_queue.empty():
99+
total += result_queue.get()
100+
print(total)
101+
end = time()
102+
print('Execution time: ', (end - start), 's', sep='')
103+
104+
105+
if __name__ == '__main__':
106+
main()
107+
108+
```
109+
110+
以上代码保存为 multi_process.py
111+
112+
```python showLineNumbers
113+
!python multi_process.py
114+
```
115+
116+
```python showLineNumbers
117+
# 5000000050000000
118+
# Execution time: 0.7936668395996094s
119+
```
120+
121+
明显,多进程更快。
122+
123+
使用多进程后由于获得了更多的 CPU 执行时间以及更好的利用了 CPU 的多核特性,明显的减少了程序的执行时间,而且计算量越大效果越明显。
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
sidebar_position: 4
3+
title: queue
4+
---

0 commit comments

Comments
 (0)