import threading
counter = 0
def increment():
global counter
for _ in range(100000):
counter += 1 # 非原子操作:读取、修改、写入
threads = [threading.Thread(target=increment) for _ in range(2)]
for t in threads:
t.start()
for t in threads:
t.join()
print(counter) # 输出可能小于 200000
上述代码中,
counter += 1 实际包含三步操作,线程切换可能导致中间状态被覆盖。
控制并发顺序的有效手段
为确保关键代码段的有序执行,可采用以下机制:
使用 threading.Lock 对共享资源加锁
利用 queue.Queue 实现线程间安全通信
在异步编程中通过 asyncio.Lock 协调协程访问
机制
适用场景
特点
Lock
多线程/多进程
保证临界区互斥访问
Queue
线程间数据传递
内置线程安全,解耦生产与消费
graph TD A[开始] --> B{是否获取到锁?} B -- 是 --> C[执行临界区代码] B -- 否 --> D[等待] C --> E[释放锁] D --> B E --> F[结束]
processes:指定进程池中最大进程数,默认为 CPU 核心数(os.cpu_count());
initializer:每个工作进程启动时调用的初始化函数;
initargs:传递给初始化函数的参数元组;
maxtasksperchild:单个进程在结束前最多执行的任务数,用于防止内存泄漏。
from multiprocessing import Pool
def task(x):
return x * x
if __name__ == '__main__':
with Pool(processes=4) as pool:
result = pool.map(task, [1, 2, 3, 4])
print(result) # 输出: [1, 4, 9, 16]
from multiprocessing import Pool
def task(n):
return n * n
with Pool(4) as p:
# 保持顺序
for result in p.imap(task, [3, 1, 4, 2]):
print(result) # 输出: 9, 1, 16, 4
# 不保证顺序
for result in p.imap_unordered(task, [3, 1, 4, 2]):
print(result) # 可能先输出 1, 4 等
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
data := []int{1, 2, 3, 4, 5}
for _, v := range data {
wg.Add(1)
go func(val int) {
defer wg.Done()
fmt.Println(val) // 输出不可控
}(v)
}
wg.Wait()
}
上述代码中,
fmt.Println(val) 的执行顺序依赖调度器,随着数据规模增大,竞态现象更明显。闭包捕获的
v 使用值传递避免了共享变量问题,但无法保证输出有序。
from multiprocessing import Pool
def fetch_url(url):
# 模拟网络请求
return f"Data from {url}"
urls = ["http://site1.com", "http://site2.com", ...]
with Pool(4) as p:
for result in p.imap_unordered(fetch_url, urls):
print(result)
from concurrent.futures import ThreadPoolExecutor
import requests
def fetch_url(url):
return requests.get(url).status_code
with ThreadPoolExecutor(max_workers=5) as executor:
futures = [executor.submit(fetch_url, u) for u in urls]
results = [f.result() for f in futures]