多线程、多进程、协程
进程(’资源单位’):运行中的程序,每次我们执行一个程序,咱们的操作系统对自动的为这个程序准备一些必要的资源(例如,分配内存,创建一个能够执行的线程)
线程(’执行单位’):程序内,可以直接被CPU调度的执行过程,是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。
多线程 写法一 1 2 3 4 5 6 7 8 9 10 11 12 13 14 from threading import Threaddef func (name ): for i in range (100 ): print (name,i)if __name__=='__main__' : t1=Thread(target=func,args=('love' ,)) t2=Thread(target=func,args=('you' ,)) t3=Thread(target=func,args=('i' ,)) t2.start() t1.start() t3.start()
写法二 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from threading import Threadclass MyThread (Thread ): def _init_ (self,name ): super (MyThread,self )._init_() self .name = namel def run (self ): for i in range (100 ): print (self .name,i) if __name__='__main__' : t1=MyThread('I' ) t2=MyThread('love' ) t3=MyThread('you' ) t1.start() t2.start() t3.start()
线程池 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 from concurrent.futures import ThreadPoolExecutordef func (name,t ): time.sleep(t) for i in range (10 ): print (name) return namedef fn (res ): `打印返回的结果` print (res.result())if __name__=='__main__' : with ThreadPoolExecutor(3 ) as t: t.submit(func,'周杰伦' ,2 ).add_done_callback(fn) t.submit(func,'薛之谦' ,1 ).add_done_callback(fn) t.submit(func,'余华' ,3 ).add_done_callback(fn) result=t.map (func,['周杰伦' ,'薛之谦' ,'余华' ],[2 ,1 ,3 ]) for r in rusult: print (r)
多进程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from multiprocessing import Processdef func (name,t ): time.sleep(t) for i in range (10 ): print (name) return name if __name__=='__main__' : p1=Process(target=func,args=('i' ,)) p2=Process(target=func,args=('love' ,)) p3=Process(target=func,args=('you' ,)) p1.start() p2.start() p3.start()
进程间传递数据(中间件) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 from multiprocessing import Process,Queuefrom concurrent.futures import ThreadPoolExecutordef get_img_src (q ): q.put(src)def download (url ): print ('开始下载' ) with open ('./img.' +name,mode='wb' ) as f: resp=requests.get(url) f.write(resp.content) print ('下载完毕' ,url) def download_img (q ): with ThreadPoolExecutor(10 ) as t: while 1 : src=q.get() t.submit(download,src) if __name__=='__main__' : q=Queue() p1=Process(target=get_img_src,args=(q,)) p2=Process(target=download_img,args=(q,)) p1.start() p2.start()
**补充:在网络编程中,队列和 socket 经常结合使用,以下是一些应用场景
请求处理:服务器端可能会使用一个队列来管理来自客户端的 socket 请求。当请求到达时,它们被放入队列中,然后服务器按顺序处理这些请求。
异步处理:在处理非阻塞 I/O 时,可以使用队列来管理待处理的 socket 事件。例如,一个线程可以监听 socket 连接,并将新的连接请求放入队列中,然后由其他工作线程来处理这些连接。
消息队列:在网络应用程序中,可以使用消息队列(如 RabbitMQ、Kafka)来缓冲和转发 socket 消息,确保消息的可靠传递和处理。
**
使用场景:
多线程:任务相对统一,相互类似
多进程:多个任务相互独立,很少有交集
从免费网站抓取代理IP
验证代理IP是否可用
准备对外的接口
协程:能够更加高效的利用CPU
多任务异步协程 协程(Coroutine)是一种程序组件,它允许多个入口点用于暂停和恢复执行的函数,可以在单个线程内实现多任务的并发执行。协程提供了一种更加轻量级的并发单元,相比于线程和进程,协程间的切换开销更小,因为它们共享同一线程的堆栈空间。
协作式多任务:协程通过显式的暂停(yield)和恢复(resume)操作来切换执行,这种切换是协作式的,而非抢占式的。
轻量级:协程不像线程那样涉及操作系统的上下文切换,它们通常由程序自身控制,因此创建和切换开销较小。
非阻塞I/O操作:协程常用于执行非阻塞I/O操作,可以在等待I/O时让出CPU给其他协程执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import asyncioasync def func (): pass if __name__=='__main__' : func() event_loop=asyncio.get_event_loop() event_loop.run_until_complete(func()) asyncio.run(func())
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import asyncioimport timeasync def func1 (): print ('func1开始' ) await asyncio.sleep(1 ) print ('func1结束' )async def func2 (): print ('func2开始' ) await asyncio.sleep(2 ) print ('func2结束' ) async def func3 (): print ('func3开始' ) await asyncio.sleep(3 ) print ('func3结束' ) if __name__=='__main__' : f1=func1() f2=func2() f3=func3() tasks=[ f1, f2, f3, ] asyncio.run(asyncio.wait(tasks))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 import asyncioasync def download (url ): pass async def main (): urls=[ 'xxx.com' , 'xxx.com' , 'xxx.com' ] tasks=[] for url in urls: task=asyncio.create_task(download(url)) tasks.append(task) done,pending=await asyncio.wait(tasks) for t in done: print (t.result()) result=await asyncio.gather(*tasks,return_exceptions=True ) if __name__=='__main__' : asyncio.run(main()) event_loop=asyncio.get_event_loop() event_loop.run_until_complete(main())
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import asyncioimport aiohttpimport aiofilesasync def download (url ): async with aiohttp.ClientSession() as session: async with seesion.get(url) as resp: text=await resp.text() content=await resp.content.read() async with aiofiles.open (file_name,mode='wb' ) as f: await f.write(content)async def main (): pass if __name__=='__main__' : asyncio.run(main())