今天我们要一起探索的是Python中的并发编程,这可是提升程序速度的魔法钥匙哦!别担心,即使你是新手,我也会让你一步步成为并发小能手。
想象一下,你在咖啡馆同时处理邮件、聊天和写代码,这就是多线程的日常。在Python里,threading模块是你的得力助手。
import threadingimport timedef say_hello(name): print(f"Hello, {name}!") time.sleep(2) # 模拟耗时操作# 创建线程thread1 = threading.Thread(target=say_hello, args=("World",))thread2 = threading.Thread(target=say_hello, args=("Python",))# 启动线程thread1.start()thread2.start()# 等待所有线程完成thread1.join()thread2.join()print("All tasks done.")
这段代码创建了两个线程,分别打印不同的问候语,然后等待它们完成。记住join(),它是等待线程的守护者。
哎呀,提到多线程,不得不提Python的“独特”设计——GIL。它就像个小警察,让CPU核心轮流执行Python字节码,这意味着多线程在CPU密集型任务中并不总是更快。别灰心,对于I/O密集型任务,多线程还是很香的!
如果想真正利用多核CPU,multiprocessing模块是你的不二之选。它为每个进程创建独立的Python解释器,绕过GIL。
from multiprocessing import Processdef worker(num): print(f'Worker: {num}') time.sleep(2)if __name__ == '__main__': processes = [] for i in range(4): p = Process(target=worker, args=(i,)) processes.append(p) p.start()
每个Process都是一个独立的小世界,它们并行运行,不受GIL限制。
并发或并行虽然快,但也会带来复杂性,比如数据同步问题。记得使用锁(Lock)来避免资源冲突,就像在厨房里只有一个微波炉,大家轮流用。
from threading import Locklock = Lock()def safe_print(number): with lock: print(f'Safe print: {number}')safe_print(1)safe_print(2)
使用with语句自动管理锁,安全又方便。
想象一个工厂的流水线,队列(Queue)就是那个协调者。在多线程/进程间传递数据,非它莫属。
from queue import Queuefrom threading import Threaddef producer(queue): queue.put('Product')def consumer(queue): print(queue.get())q = Queue()producer_thread = Thread(target=producer, args=(q,))consumer_thread = Thread(target=consumer, args=(q,))producer_thread.start()consumer_thread.start()producer_thread.join()consumer_thread.join()
队列保证了数据的安全传递,避免了混乱。
等不及了?asyncio带你进入异步编程的世界,用async/await关键字,就像给你的代码加了翅膀。
import asyncioasync def hello(i): print(f'Hello {i}') await asyncio.sleep(1) # 异步等待async def main(): tasks = [hello(i) for i in range(3)] await asyncio.gather(*tasks)# Python 3.7+asyncio.run(main())
异步等待,让程序在等待时去做其他事,效率杠杠的。
虽然asyncio很强大,但并非所有函数都可以异步化,比如那些直接操作硬件的低级API。选择合适的方法,别硬塞。
想要简单地并发执行任务,不论同步还是异步,concurrent.futures是你的良师益友。
from concurrent.futures import ThreadPoolExecutordef worker(n): return n * nwith ThreadPoolExecutor() as executor: results = executor.map(worker, range(5)) print(list(results)) # 输出平方数
用ThreadPoolExecutor轻松管理线程池,执行任务就像点菜一样简单。
并发中错误处理很重要,使用try-except来保护你的代码,确保一个任务的失败不会影响到整个程序。
try: # 可能会出错的并发代码except Exception as e: print(f'Caught an exception: {e}')
保持冷静,优雅处理,你的程序更健壮。
with语句不仅仅是为了代码简洁,它还能确保资源(如文件、锁)的正确释放,避免并发中的资源泄露。
with Lock(): # 在这里安全地操作共享资源
自动的开始与结束,像一位细心的管家。
使用timeit, cProfile等工具来监控你的并发程序,了解哪些部分慢如蜗牛,哪些是速度恶魔,优化从了解开始。
最后,让我们实战一把,用多线程下载图片,感受并发的魅力。
import osimport requestsfrom threading import Threaddef download_image(url, filename): response = requests.get(url) with open(filename, 'wb') as f: f.write(response.content) print(f'{filename} downloaded.')urls = ['img_url1', 'img_url1'] # 假设的URLthreads = []for url in urls: t = Thread(target=download_image, args=(url, os.path.basename(url))) threads.append(t) t.start()for t in threads: t.join()print('All images downloaded.')
通过并发下载,我们可以显著加快下载速度!
到这里,我们已经解锁了Python并发编程的12个实用技巧,是不是感觉自己的编程技能又上了一个新台阶?实践是检验真理的唯一标准,赶紧动手试试,让你的程序跑得飞起来吧!
本文链接:http://www.28at.com/showinfo-26-90039-0.htmlPython 并发编程的 12 个实用技巧
声明:本网页内容旨在传播知识,不代表本站观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。
上一篇:阿里面试:说说自适应限流?