1/Python中的同步调用与异步调用
<1>同步调用 (Synchronous Calls)
同步调用是指代码按顺序执行,每个操作必须等待前一个操作完成后才能开始。这是默认的程序执行方式。
同步调用的特点:
- 顺序执行,易于理解和调试
- 阻塞式操作,当前操作完成前不能执行其他代码
- 适合简单、线性的任务
同步实现方式:
- 普通函数调用
- 直接执行代码
<2>异步调用 (Asynchronous Calls)
异步调用是指代码可以在等待某个操作完成时继续执行其他任务,而不是阻塞等待。
异步调用的特点:
- 非阻塞,提高程序效率
- 适合I/O密集型任务(网络请求、文件读写等)
- 代码结构更复杂,需要事件循环
异步实现方式:
asyncio库 (Python 3.5+)async/await关键字- 回调函数
- 线程/进程池
2/完整示例
示例1:同步调用示例
import time
def sync_task(name, delay):
"""模拟一个耗时的同步任务"""
print(f"任务 {name} 开始执行,需要 {delay} 秒")
time.sleep(delay) # 模拟耗时操作
print(f"任务 {name} 完成")
return f"任务 {name} 结果"
def synchronous_example():
"""同步调用示例"""
print("=== 同步调用示例 ===")
start_time = time.time()
# 顺序执行任务
result1 = sync_task("A", 2)
result2 = sync_task("B", 1)
result3 = sync_task("C", 3)
end_time = time.time()
print(f"\n所有任务完成!")
print(f"结果: {result1}, {result2}, {result3}")
print(f"总耗时: {end_time - start_time:.2f} 秒")
if __name__ == "__main__":
synchronous_example()
示例2:使用asyncio的异步调用
import asyncio
import time
async def async_task(name, delay):
"""模拟一个耗时的异步任务"""
print(f"异步任务 {name} 开始执行,需要 {delay} 秒")
await asyncio.sleep(delay) # 异步等待,不会阻塞事件循环
print(f"异步任务 {name} 完成")
return f"异步任务 {name} 结果"
async def asynchronous_example():
"""异步调用示例"""
print("=== 异步调用示例 ===")
start_time = time.time()
# 创建任务但不立即等待
task1 = asyncio.create_task(async_task("A", 2))
task2 = asyncio.create_task(async_task("B", 1))
task3 = asyncio.create_task(async_task("C", 3))
# 等待所有任务完成
results = await asyncio.gather(task1, task2, task3)
end_time = time.time()
print(f"\n所有异步任务完成!")
print(f"结果: {results}")
print(f"总耗时: {end_time - start_time:.2f} 秒")
async def asynchronous_with_timeout():
"""带有超时控制的异步调用示例"""
print("\n=== 异步调用(带超时)示例 ===")
try:
# 设置任务超时时间
result = await asyncio.wait_for(async_task("D", 5), timeout=3.0)
print(f"任务完成: {result}")
except asyncio.TimeoutError:
print("任务超时!")
def run_async_examples():
"""运行异步示例"""
# 运行基本异步示例
asyncio.run(asynchronous_example())
# 运行带超时的异步示例
asyncio.run(asynchronous_with_timeout())
if __name__ == "__main__":
run_async_examples()
示例3:使用线程池的异步调用
import concurrent.futures
import time
import random
def cpu_intensive_task(name, iterations):
"""模拟一个CPU密集型任务"""
print(f"CPU任务 {name} 开始执行")
result = 0
for i in range(iterations):
result += i * random.random()
print(f"CPU任务 {name} 完成")
return f"CPU任务 {name} 结果: {result}"
def io_intensive_task(name, delay):
"""模拟一个I/O密集型任务"""
print(f"IO任务 {name} 开始执行,需要 {delay} 秒")
time.sleep(delay) # 模拟I/O等待
print(f"IO任务 {name} 完成")
return f"IO任务 {name} 结果"
def thread_pool_example():
"""使用线程池的异步调用示例"""
print("=== 线程池异步调用示例 ===")
start_time = time.time()
# 使用线程池执行I/O密集型任务
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
# 提交任务到线程池
future1 = executor.submit(io_intensive_task, "A", 2)
future2 = executor.submit(io_intensive_task, "B", 1)
future3 = executor.submit(io_intensive_task, "C", 3)
# 获取结果
results = []
for future in concurrent.futures.as_completed([future1, future2, future3]):
result = future.result()
results.append(result)
print(f"获取到结果: {result}")
end_time = time.time()
print(f"\n所有线程池任务完成!")
print(f"总耗时: {end_time - start_time:.2f} 秒")
def process_pool_example():
"""使用进程池的异步调用示例(适合CPU密集型任务)"""
print("\n=== 进程池异步调用示例 ===")
start_time = time.time()
# 使用进程池执行CPU密集型任务
with concurrent.futures.ProcessPoolExecutor(max_workers=3) as executor:
# 提交任务到进程池
futures = [
executor.submit(cpu_intensive_task, f"任务{i}", 10000000)
for i in range(1, 5)
]
# 获取结果
for future in concurrent.futures.as_completed(futures):
result = future.result()
print(f"获取到结果: {result}")
end_time = time.time()
print(f"\n所有进程池任务完成!")
print(f"总耗时: {end_time - start_time:.2f} 秒")
if __name__ == "__main__":
thread_pool_example()
process_pool_example()
示例4:混合使用同步和异步
import asyncio
import time
import aiohttp
import requests
# 同步网络请求函数
def sync_fetch_url(url):
"""同步获取网页内容"""
print(f"同步请求: {url}")
response = requests.get(url, timeout=5)
print(f"同步请求完成: {url}, 状态码: {response.status_code}")
return response.status_code
# 异步网络请求函数
async def async_fetch_url(session, url):
"""异步获取网页内容"""
print(f"异步请求: {url}")
async with session.get(url, timeout=5) as response:
print(f"异步请求完成: {url}, 状态码: {response.status}")
return response.status
async def mixed_example():
"""混合使用同步和异步的示例"""
print("=== 混合同步/异步示例 ===")
start_time = time.time()
# 同步请求
print("\n1. 执行同步请求...")
sync_start = time.time()
sync_result = sync_fetch_url("https://httpbin.org/get")
print(f"同步请求耗时: {time.time() - sync_start:.2f} 秒")
# 异步请求
print("\n2. 执行异步请求...")
async_start = time.time()
# 创建多个异步任务
urls = [
"https://httpbin.org/delay/1",
"https://httpbin.org/delay/2",
"https://httpbin.org/status/200",
"https://httpbin.org/status/404"
]
async with aiohttp.ClientSession() as session:
tasks = [async_fetch_url(session, url) for url in urls]
async_results = await asyncio.gather(*tasks, return_exceptions=True)
print(f"异步请求耗时: {time.time() - async_start:.2f} 秒")
end_time = time.time()
print(f"\n所有任务完成!")
print(f"同步结果: {sync_result}")
print(f"异步结果: {async_results}")
print(f"总耗时: {end_time - start_time:.2f} 秒")
def run_mixed_example():
"""运行混合示例"""
asyncio.run(mixed_example())
if __name__ == "__main__":
run_mixed_example()
示例5:回调函数方式的异步调用
import threading
import time
import queue
def long_running_task(task_id, duration, callback):
"""模拟长时间运行的任务,完成后调用回调函数"""
def task():
print(f"任务 {task_id} 开始执行,需要 {duration} 秒")
time.sleep(duration)
result = f"任务 {task_id} 完成,耗时 {duration} 秒"
# 执行回调函数
callback(result)
# 在新线程中执行任务
thread = threading.Thread(target=task)
thread.start()
return thread
def callback_example():
"""使用回调函数的异步调用示例"""
print("=== 回调函数异步调用示例 ===")
start_time = time.time()
# 创建队列用于收集结果
result_queue = queue.Queue()
# 定义回调函数
def task_callback(result):
print(f"回调函数收到: {result}")
result_queue.put(result)
# 启动多个异步任务
threads = []
for i, duration in enumerate([2, 1, 3], 1):
thread = long_running_task(i, duration, task_callback)
threads.append(thread)
# 等待所有线程完成
for thread in threads:
thread.join()
# 收集结果
results = []
while not result_queue.empty():
results.append(result_queue.get())
end_time = time.time()
print(f"\n所有回调任务完成!")
print(f"结果: {results}")
print(f"总耗时: {end_time - start_time:.2f} 秒")
if __name__ == "__main__":
callback_example()
总结对比
| 特性 | 同步调用 | 异步调用 |
|---|---|---|
| 执行方式 | 顺序执行,阻塞 | 非阻塞,可并发 |
| 代码复杂度 | 简单直观 | 相对复杂 |
| 适用场景 | 简单任务、CPU密集型 | I/O密集型、高并发 |
| 性能 | 较低(等待时间长) | 较高(资源利用率高) |
| 实现方式 | 普通函数调用 | asyncio、线程池、进程池、回调 |
选择建议
-
使用同步调用当:
- 任务简单,不需要并发
- 代码可读性和简单性是首要考虑
- 任务之间有明显依赖关系
-
使用异步调用当:
- 有大量I/O操作(网络请求、文件读写)
- 需要高并发处理
- 程序性能是关键考虑因素
-
选择异步实现方式:
- asyncio:Python原生支持,适合I/O密集型任务
- 线程池:适合I/O密集型任务,简单易用
- 进程池:适合CPU密集型任务,避免GIL限制
- 回调函数:传统异步模式,控制灵活但代码复杂
这些示例展示了Python中同步和异步调用的不同实现方式,你可以根据具体需求选择合适的方法。