python thread VS async

本文探讨了async代码相较于threading的三个优势:代码线程安全性增强,内存占用更少,以及对平台资源需求较低。通过实例说明了如何避免竞态条件和共享栈的问题,以及async如何简化内存管理。

python - Threads vs. Async - Stack Overflow

https://krondo.com/in-which-we-begin-at-the-beginning/

与threading相比, async的优势表现为3点:

  1. It is very difficult to write code that is thread safe. With asyncronous code, you know exactly where the code will shift from one task to the next and race conditions are therefore much harder to come by.
  2. Threads consume a fair amount of data since each thread needs to have its own stack. With async code, all the code shares the same stack and the stack is kept small due to continuously unwinding the stack between tasks.
  3. Threads are OS structures and are therefore more memory for the platform to support. There is no such problem with asynchronous tasks.

大致意思:

1. 代码很难保证线程时安全的,而async 代码,可以很清楚的看到代码之间的调换/执行过程

2.每个线程有自己单独的栈,而async代码之间共享栈

3. 线程比较耗内存

### Python MainThread 线程卡死的原因分析 当遇到 `MainThread` 卡死的情况时,通常是因为某些阻塞操作未能及时释放资源或完成执行。具体原因可能涉及多个方面: - **I/O 阻塞**:长时间运行的 I/O 操作可能导致主线程无法继续处理其他任务[^1]。 - **锁机制不当使用**:如全局解释器锁(GIL)、互斥锁等未正确管理,可能会引发死锁现象[^2]。 - **子进程通信异常**:如果通过 `multiprocessing.Queue` 或者类似的 IPC 方式进行跨进程数据交换时出现问题,则容易造成整个应用程序停滞不前[^3]。 针对上述情况,可以采取如下措施来预防并解决问题: #### 使用非阻塞方式替代同步等待 对于那些会触发网络请求或其他形式外部交互的任务来说,建议采用异步编程模型或是回调函数的方式来进行设计,从而避免因单一线程被占用而影响到整体性能表现。 ```python import asyncio async def fetch_data(url): print(f"Fetching data from {url}") await asyncio.sleep(1) # Simulate network delay with sleep. return {"status": "success", "data": []} async def main(): urls = ["http://example.com"] * 5 tasks = [fetch_data(url) for url in urls] results = await asyncio.gather(*tasks) print(results) if __name__ == "__main__": loop = asyncio.get_event_loop() try: loop.run_until_complete(main()) finally: loop.close() ``` 此代码片段展示了如何利用 `asyncio` 库实现并发 HTTP 请求而不必担心它们会使主事件循环陷入僵局状态。 #### 正确配置日志记录模块 为了避免由于多线程或多进程中共享同一个文件句柄而导致的竞争条件问题,在设置 logging handler 的时候应该特别注意其参数的选择以及初始化时机。 ```python import logging.handlers from multiprocessing import current_process, Queue as MPQueue from threading import Thread def worker_init(q: MPQueue): h = logging.handlers.QueueHandler(q) logger = logging.getLogger() logger.addHandler(h) logger.setLevel(logging.INFO) queue = MPQueue(-1) listener = logging.handlers.QueueListener( queue, *[logging.FileHandler('app.log')], respect_handler_level=True ) listener.start() for i in range(4): # Create four workers. p = Process(target=worker_target, args=(i,), kwargs={'q': queue}) processes.append(p) p.daemon = True p.start() # Ensure all logs are processed before exit. listener.stop() ``` 这里展示了一个安全的日志收集模式——即让各个工作单元向中心队列发送消息,再由专门监听该队列的服务负责实际写入磁盘的操作;这样既能够保持良好的响应速度又不会引起潜在冲突。 #### 合理规划进程间通讯渠道 在创建新的子进程之前,请务必确认所使用的管道、套接字或者其他任何类型的连接对象已经被妥善关闭,并且没有任何残留的数据包滞留在缓冲区内待传输完毕后再结束对应的工作流程。 ```python from multiprocessing import Pool, Manager def process_item(item_id, shared_dict): result = do_heavy_computation(item_id) lock.acquire() # Use a manager-based Lock to synchronize access between processes. try: shared_dict[item_id] = result finally: lock.release() with Manager() as mgr: items_to_process = list(range(8)) output_storage = mgr.dict() pool = Pool(processes=len(items_to_process)) async_results = [ pool.apply_async(process_item, (item, output_storage)) for item in items_to_process] _ = [res.wait(timeout=None) for res in async_results] final_output = dict(output_storage.items()) pool.join() ``` 这段示范说明了怎样借助于 `Manager()` 提供的安全容器类来协调不同实例间的协作关系,同时确保所有必要的清理动作都能被执行到位。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值