|
|
|
@ -1,8 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
对于 **I/O 密集型任务**,**异步编程** 通常比 **多线程** 是更好的选择。异步编程特别适合高并发的 I/O 密集型任务(如 Web 服务器、爬虫、实时通信), 特别是大量并发连接的任务。
|
|
|
|
|
异步编程特别适合高并发的 I/O 密集型任务(如 Web 服务器、爬虫、实时通信), 特别是大量并发连接的任务。
|
|
|
|
|
对于 **I/O 密集型任务**,**异步编程** 通常比 **多线程** 是更好的选择。
|
|
|
|
|
多线程相对编程简单 。
|
|
|
|
|
|
|
|
|
|
多线程比相对编程简单 。
|
|
|
|
|
但,以下场景更适合使用 **多线程**:
|
|
|
|
|
|
|
|
|
|
### 场景:**GUI 应用程序**
|
|
|
|
|
|
|
|
|
@ -92,11 +94,10 @@ if __name__ == "__main__":
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
以下场景更适合使用 **多线程**:
|
|
|
|
|
-
|
|
|
|
|
**与阻塞式 API 交互**。
|
|
|
|
|
某些库或 API 是阻塞式的(如某些数据库驱动、硬件接口库),无法直接使用异步编程。在这种情况下,多线程可以避免阻塞主线程。
|
|
|
|
|
### 场景:**与阻塞式 API 交互**
|
|
|
|
|
|
|
|
|
|
某些库或 API 是阻塞式的(如某些数据库驱动、硬件接口库),无法直接使用异步编程。在这种情况下,多线程可以避免阻塞主线程。
|
|
|
|
|
```python
|
|
|
|
|
import threading
|
|
|
|
|
import time
|
|
|
|
|
import sqlite3
|
|
|
|
@ -123,12 +124,99 @@ def main():
|
|
|
|
|
print("主线程结束")
|
|
|
|
|
|
|
|
|
|
main()
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**实时数据处理**。 在实时数据处理场景中(如音频处理、视频流处理),需要快速响应并处理数据,同时保持主线程的响应性。
|
|
|
|
|
### 场景:**任务队列与线程池**
|
|
|
|
|
|
|
|
|
|
**任务队列与线程池**。在需要处理大量短期任务的场景中(如 Web 服务器的请求处理),使用线程池可以高效地管理任务。
|
|
|
|
|
在需要处理大量短期任务的场景中(如 Web 服务器的请求处理),使用线程池可以简单编程实现高效地管理任务。
|
|
|
|
|
特别类似上面场景,有些任务是阻塞式的,不支持异步
|
|
|
|
|
|
|
|
|
|
**与 C/C++ 扩展交互**。 某些 Python 库是基于 C/C++ 扩展实现的(如 `numpy`、`pandas`),这些扩展可能释放了 GIL,允许在多线程中并行运行。
|
|
|
|
|
```python
|
|
|
|
|
import concurrent.futures
|
|
|
|
|
import time
|
|
|
|
|
|
|
|
|
|
def process_task(task):
|
|
|
|
|
print(f"开始处理任务: {task}")
|
|
|
|
|
time.sleep(2) # 模拟任务处理时间
|
|
|
|
|
print(f"完成处理任务: {task}")
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
print("主线程开始")
|
|
|
|
|
tasks = ["task1", "task2", "task3", "task4", "task5"]
|
|
|
|
|
# 使用线程池处理任务
|
|
|
|
|
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
|
|
|
|
|
executor.map(process_task, tasks)
|
|
|
|
|
print("主线程结束")
|
|
|
|
|
|
|
|
|
|
**需要共享状态的场景**。 在某些场景中,多个任务需要频繁共享和修改状态(如缓存、计数器),使用多线程可以方便地共享内存。
|
|
|
|
|
main()
|
|
|
|
|
````
|
|
|
|
|
|
|
|
|
|
### 场景:**与 C/C++ 扩展交互**
|
|
|
|
|
|
|
|
|
|
某些 Python 库是基于 C/C++ 扩展实现的(如 `numpy`、`pandas`),这些扩展可能释放了 GIL,允许在多线程中并行运行。
|
|
|
|
|
多线程常常更快 。
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
import threading
|
|
|
|
|
import numpy as np
|
|
|
|
|
|
|
|
|
|
def compute_task(data):
|
|
|
|
|
result = np.sum(data)
|
|
|
|
|
print(f"计算结果: {result}")
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
print("主线程开始")
|
|
|
|
|
data = np.random.rand(1000000) # 生成随机数据
|
|
|
|
|
# 创建多个线程并行计算
|
|
|
|
|
threads = []
|
|
|
|
|
for i in range(4):
|
|
|
|
|
thread = threading.Thread(target=compute_task, args=(data,))
|
|
|
|
|
thread.start()
|
|
|
|
|
threads.append(thread)
|
|
|
|
|
for thread in threads:
|
|
|
|
|
thread.join()
|
|
|
|
|
print("主线程结束")
|
|
|
|
|
|
|
|
|
|
main()
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 场景:**需要共享状态**
|
|
|
|
|
|
|
|
|
|
在某些场景中,多个任务需要频繁共享和修改状态(如缓存、计数器),使用多线程可以方便地共享内存。
|
|
|
|
|
线程之间可以直接访问和修改共享变量。
|
|
|
|
|
异步任务之间是独立的,不能直接共享变量或状态。
|
|
|
|
|
如果需要在任务之间共享状态,必须通过显式的机制(如队列、回调函数)来传递数据。
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
import threading
|
|
|
|
|
|
|
|
|
|
class Counter:
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.value = 0
|
|
|
|
|
self.lock = threading.Lock()
|
|
|
|
|
|
|
|
|
|
def increment(self):
|
|
|
|
|
with self.lock:
|
|
|
|
|
self.value += 1
|
|
|
|
|
print(f"计数器值: {self.value}")
|
|
|
|
|
|
|
|
|
|
def worker(counter):
|
|
|
|
|
for _ in range(5):
|
|
|
|
|
counter.increment()
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
print("主线程开始")
|
|
|
|
|
counter = Counter()
|
|
|
|
|
# 创建多个线程共享计数器
|
|
|
|
|
threads = []
|
|
|
|
|
for i in range(3):
|
|
|
|
|
thread = threading.Thread(target=worker, args=(counter,))
|
|
|
|
|
thread.start()
|
|
|
|
|
threads.append(thread)
|
|
|
|
|
for thread in threads:
|
|
|
|
|
thread.join()
|
|
|
|
|
print("主线程结束")
|
|
|
|
|
|
|
|
|
|
main()
|
|
|
|
|
```
|
|
|
|
|