1. 为什么需要并发编程?
  1. 如果程序中包含I/O操作,程序会有很高的延迟,CPU会处于等待状态,这样会浪费系统资源,浪费时间
  1. 1.Python的并发编程分为多进程并发和多线程并发
  1. 多进程并发:运行多个独立的程序,优势在于并发处理的任务都有操作系统管理,不足的是程序和各个进程间通信和数据共享不方便
  2. 多线程并发:有程序员管理并发处理人物,这种并发的可以方便的在线程间共享数据,前提是不能被锁住
  1. 对于计算密集型程序:多进程并发优于多线程并发,计算密集型指的是:程序运行的时间大部分都消耗在cpu的运算处理过程中,而对内存磁盘的消耗时间较短对于i/o密集型程序:多线程并发优于多进程并发,i/o密集型与计算密集型正好相反
  1. 2.python支持的多进程并发有两种方式
  1. 1.通过进程安全的数据结构:multiprocess.JoinableQueue:这种数据结构程序员自己管理'加锁'过程,不用担心死锁问题
  2. 2.通过concurr.futures抽象出来的ProcessPollExecutor
  1. multiprocessJoinableQueue
  1. multiprocess(是进程间安全的) Python标准库中的支持进程的模块,JoinableQueue队列本质上是FIFO队列,
  2. 与一般的队列(queue中的Queue)区别在于:JoinableQueue是能支持多进程并发和保证进程间的数据通信,
  3. 是进程间安全的,这意味着我们不用担心它的互斥和死锁问题,JoinableQueue主要可以用来存放执行任务和收集任务的执行结果
  4. JoinableQueue队列为什么是进程间安全的?
  5. 因为不管什么队列,都是自带了锁,所中的上下文管理中(with)包含了acquire()和release()方法。
  6. 队列基于文件家族的socket实现的,队列中是有管道(pipe)和锁实现的。
  1. from multiprocessing import JoinableQueue,Process,current_process
  2. def consumer(jq,name):
  3. while True:
  4. word = jq.get()
  5. print('%s 取到了%s'%(name,word))
  6. jq.task_done()
  7. # print(jq.task_done())
  8.  
  9. def print_word(jq,produce_name):
  10. for c in [chr(ord('A')+i) for i in range(26)]:
  11. jq.put(c)
  12. print("%s 生产了一个 %s"%(produce_name,c))
  13. jq.join()
  14.  
  15. if __name__ == '__main__':
  16. jq = JoinableQueue() #不管用什么队列,都必须要先实例化
  17. produce_name = 'admin'
  18. # consumer_list = ['kobe','t-mac']
  19. pn = Process(target=print_word,args=(jq,produce_name))
  20. tt1 = Process(target=consumer, args=(jq,'kobe'))
  21. tt2 = Process(target=consumer, args=(jq,'t-mac'))
  22. tt1.daemon =True
  23. tt2.daemon =True
  24. tt1.start()
  25. tt2.start()
  26. pn.start()
  27. pn.join()
  28.  
  29. '''
  30. 使用JoinableQueue实现多线程搞得时候要注意这几个方法的关联
  31. 1.pn.join() 为什么子线程pn要设置阻塞?
  32. 首先要知道join方法是Process提供来管理子进程的,在同步阻塞的时候,只关心子线程是否执行完毕,只要子线程结束,才会执行阻塞后的代码
  33. 2.jq.join()为什么子进程设置阻塞?
  34. 因为jq要等待consumer方法将全部的字母取走,只要consumer将全部的字母取走之后,jq才不阻塞了,代表着print_word方法已经将工作做完了
  35. jq.join()在这里可以理解成:当队列为空我才不阻塞了,
  36. 3.jq.task_done()是什么意思?
  37. 通知producer里面的jq.join(),要将队列里面的计数器-1,因为有一个数据被取走了,当所有的任务处理完之后,队列的计数器为0
  38. 也就是队列为空了,这是jq.join()就不阻塞了
  39. 4.那tt1.daemon =True和tt2.daemon =True子进程为什么要设置成守护进程?
  40. 我们子啊consumer里面写的是while True,理解是这个死循环永远不能退出
  41. 但是守护进程会随着主进程的运行完毕之后跟着结束,我们退出不了while,那把主进程kill掉,也就退出了死循环
  42. 所以:
  43. pn.join()在等待这自己的子进程函数print_word执行完毕,因为执行到主线程搞得代码结束为止,所以主线程退出
  44. 但是print_word()子线程里面的jq.join()也在阻塞这,等待jq.task_done()发过来的最后一个信号,也就是队列为空
  45. 所以,当jq.task_done()发空信号之后jq.join()不阻塞,然后pn.join()不阻塞,程序结束
  46. 而进程中的守护进程的特点是随着主进程的结束而结束,所以整个程序结束,name死循环也就结束了。
  47.  
  48. 理解task_done():
  49. 如果进程或线程每从队列里取一次,但没有执行task_done(),则join无法判断队列到底有没有结束,在最后执行个join()是等不到结果的,会一直挂起。
  50. 可以理解为,每task_done一次 就从队列里删掉一个元素,这样在最后join的时候根据队列长度是否为零来判断队列是否结束,从而执行主线程。
  51. '''

multiprocessing中的JoinableQueue实现多进程并发

  1. concurrent.futuresProcessPoolExecutor
  1. from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
  2. ThreadPoolExecutor ProcessPoolExecutor分别对threadingmultiprocessing进行了高级抽象,暴露出简单的统一接口。
  3.  
  4. future 是一种对象,表示异步执行的操作。这个概念是 concurrent.futures模块和asyncio包的基础。
  5. Python3.4起,标准库中有两个为Future的类:concurrent.futures.Future asyncio.Future
  6. 这两个类作用相同:两个Future类的实例都表示可能已经完成或未完成的延迟计算。
  7. Future 封装待完成的操作,可放入队列,完成的状态可以查询,得到结果(或抛出异常)后可以获取结果(或异常)。
  1. import os,time
  2. from urllib.request import urlopen
  3. from concurrent.futures import ProcessPoolExecutor
  4.  
  5. def get_html(name,addr):
  6. ret = urlopen(addr)
  7. return {'name': name, 'content': ret.read()}
  8.  
  9. def print_info(connect):
  10. dic = connect.result()
  11. with open(dic['name']+'.html',mode='wb') as f:
  12. f.write(dic['content'])
  13.  
  14. if __name__ == '__main__':
  15. start = time.time()
  16. url_list = {
  17. '百度':'https://www.baidu.com',
  18. 'p0st':'https://www.cnblogs.com/p0st/p/10453405.html',
  19. 'jd':'https://www.jd.com',
  20. '博客园':'https://www.cnblogs.com',
  21. 'a':'https://www.baidu.com',
  22. 'b': 'https://www.cnblogs.com/p0st/p/10453405.html',
  23. 'c': 'https://www.jd.com',
  24. 'd': 'https://www.cnblogs.com'
  25. }
  26. p = ProcessPoolExecutor(4)
  27. for item in url_list:
  28. task = p.submit(get_html,item,url_list[item]).add_done_callback(print_info)
  29. task.add_done_callback(print_info)
  30. #使用submit向进程池中添加任务,返回的时一个future对象,使用result从中取值
  31. #在此过程中是并发的去执行的
  32. #p.submit(get_html,item,url_list[item]).add_done_callback(print_info)
  33. #add_done_callback 回调函数,将task
  34. p.shutdown()
  35. # 阻塞主进程 直到池中的任务都完成为止,然后进程还会回到进程池里面等待任务
  36. print(time.time()-start)
  37.  
  38. #with ProcessPoolExecutor(4) as p:
  39. # for item in url_list:
  40. # p.submit(get_html, item, url_list[item]).add_done_callback(print_info)
  41. # p.shutdown()
  42. #print(time.time() - start)
  43. '''
  44. #ret = p.map(make, range(100)) 是for循环的简便写法,一般只用于传递一个参数
  45. #ret=返回的是返回的是生成器,再循环就可以了
  46.  
  47. #如果task.result()执行修改完了之后才会返回结果,但是如果没执行完,就会等待,所以是一个阻塞方法
  48. #如果有可能发生阻塞的方法,那个这个方法就是阻塞方法
  49.  
  50. '''
  51. concurrent.futures中的ProcessPoolExecutor实现多进程并发

concurrent.futures中的ProcessPoolExecutor实现多进程并发

  1. 3.python中的多线程并发也有两种方式
  1. 对于IO密集型程序,多线程并发可能要优于多进程并发。因为对于网络通信等IO密集型任务来说,决定程序效率的主要是网络延迟,这时候是使用进程还是线程就没有太大关系了。
  2.  
  3. 程序与多进程基本一致,只是这里我们不必使用multiProcessing.JoinableQueue对象了,一般的队列(来自queue.Queue)就可以满足要求:
  1. from queue import Queue
  1. def read(q):
  2. while True:
  3. try:
  4. value = q.get()
  5. print('Get %s from queue.' % value)
  6. time.sleep(random.random())
  7. finally:
  8. q.task_done()
  9.  
  10. def main():
  11. q = queue.Queue()
  12. pw1 = threading.Thread(target=read, args=(q,))
  13. pw2 = threading.Thread(target=read, args=(q,))
  14. pw1.daemon = True
  15. pw2.daemon = True
  16. pw1.start()
  17. pw2.start()
  18. for c in [chr(ord('A')+i) for i in range(26)]:
  19. q.put(c)
  20. try:
  21. q.join()
  22. except KeyboardInterrupt:
  23. print("stopped by hand")
  24.  
  25. if __name__ == '__main__':
  26. main()

queuq中Queue实现多线程并发

  1. concurrent.futuresThreadPoolExecutor
  1.  
  1. concurrent.futuresThreadPoolExecutor抽象接口不仅可以帮我们自动调度线程,还能:  1.主线程可以获取某一个线程(或者任务的)的状态,以及返回值。  2.当一个线程完成的时候,主线程能够立即知道。  3.让多线程和多进程的编码接口一致。
  1. 1、建立线程池:executor = ThreadPoolExecutor(max_workers= )
  2. 2、提交执行函数到线程池:task = executor.submit(func,(args))
  3. 3、获取执行结果:task.result()
  4. 4、判断线程是否完成:task.done()
  5. 5、取消还没执行的线程:task.cancel()
  6. 6、利用as_completed获取线程完成结果,返回迭代器
  7. 7、通过executormap获取已经完成的task
  8. for data in executor.map(get_html,urls):
  9. print(data)
  10. 8、使用wait()方法阻塞线程

ThreadPoolExecutor方法

  1. from urllib.request import urlopen
  2. from concurrent.futures import ThreadPoolExecutor
  3. def get_html(name,addr):
  4. ret = urlopen(addr)
  5. return {'name': name, 'content': ret.read()}
  6.  
  7. def print_info(connect):
  8. dic = connect.result()
  9. with open(dic['name']+'.html',mode='wb') as f:
  10. f.write(dic['content'])
  11. url_list = {
  12. '百度':'https://www.baidu.com',
  13. 'p0st':'https://www.cnblogs.com/p0st/p/10453405.html',
  14. 'jd':'https://www.jd.com',
  15. '博客园':'https://www.cnblogs.com',
  16. 'a':'https://www.baidu.com',
  17. 'b': 'https://www.cnblogs.com/p0st/p/10453405.html',
  18. 'c': 'https://www.jd.com',
  19. 'd': 'https://www.cnblogs.com'
  20. }
  21. t = ThreadPoolExecutor(4)
  22. if __name__ == '__main__':
  23. for item in url_list:
  24. task = t.submit(get_html,item,url_list[item]) #回调函数,当执行完task后,立即将返回值传给回调函数
  25. task.add_done_callback(print_info)
  26. # 回调函数,当执行完task后,立即将返回值传给回调函数

concurrent.futures中的ThreadPoolExecutor实现多线程并发

  1. with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
  2. print(list(executor.map(sleeper, x)))

ThreadPoolExecutor高级写法

  1. from concurrent.futures import ProcessPoolExecutor
  2. def pool_factorizer_go(nums, nprocs):
  3. nprocs=xxx
  4. with ProcessPoolExecutor(max_workers=nprocs) as executor:
  5. return {num:factors for num, factors in
  6. zip(nums,
  7. executor.map(factorize_naive, nums))}

ProcessPoolExecutor高级写法

  1. #在一个函数中等待另一个结果的完毕。
  2. import time
  3. def wait_on_b():
  4. time.sleep(5)
  5. print(b.result()) #b不会完成,他一直在等待a的return结果
  6. return 5
  7.  
  8. def wait_on_a():
  9. time.sleep(5)
  10. print(a.result()) #同理a也不会完成,他也是在等待b的结果
  11. return 6
  12.  
  13. executor = ThreadPoolExecutor(max_workers=2)
  14. a = executor.submit(wait_on_b)
  15. b = executor.submit(wait_on_a)

多线程或多进程中死锁的列子

4.进程/线程中创建协程

  1. from multiprocessing import Process
  2.  
  3. from gevent import monkey;monkey.patch_all()
  4. import gevent
  5. import time
  6. import random
  7. class Sayhi(Process):
  8. def __init__(self,name):
  9. super().__init__()
  10. self.name = name
  11.  
  12. @staticmethod
  13. def func(item):
  14. time.sleep(random.uniform(1,2))
  15. print('协程:sayhi %s'%item)
  16.  
  17. def run(self):
  18. count = 20
  19. ll= []
  20. for item in range(count):
  21. gg = gevent.spawn(self.func,item)
  22. ll.append(gg)
  23. gevent.joinall(ll)
  24.  
  25. if __name__ == '__main__':
  26. p = Sayhi('kobe')
  27. p.start()
  28. p.join()

进程中创建协程

  1. import os
  2. from gevent import monkey;monkey.patch_all()
  3. import time
  4. import random
  5. import gevent
  6. from threading import Thread
  7. class Sayhi(Thread):
  8. def __init__(self,name):
  9. super().__init__()
  10. self.name = name
  11.  
  12. @staticmethod
  13. def func(item):
  14. time.sleep(random.uniform(1,2))
  15. print('协程:sayhi %s %s'%(item,os.getpid()))
  16.  
  17. def run(self):
  18. count = 20
  19. l = []
  20. for i in range(count):
  21. g = gevent.spawn(self.func,i)
  22. l.append(g)
  23. gevent.joinall(l)
  24. if __name__ == '__main__':
  25. p = Sayhi('kobe')
  26. p.start()
  27. p.join()
  28. print(os.getpid())
  29.  
  30. 线程里面开启协程

线程中创建协程

asyncino  yiled from 拉拉

ProcessPoolExecutor资料

  1.  
  1.  
  2. 返回系列

python多进程并发和多线程并发和协程的更多相关文章

  1. python 多进程并发与多线程并发

    本文对python支持的几种并发方式进行简单的总结. Python支持的并发分为多线程并发与多进程并发(异步IO本文不涉及).概念上来说,多进程并发即运行多个独立的程序,优势在于并发处理的任务都由操作 ...

  2. Python开发【第九篇】:协程、异步IO

    协程 协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是协程,协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他地方,在切换回 ...

  3. (转)Python黑魔法 --- 异步IO( asyncio) 协程

    转自:http://www.jianshu.com/p/b5e347b3a17c?from=timeline Python黑魔法 --- 异步IO( asyncio) 协程 作者 人世间 关注 201 ...

  4. Python、进程间通信、进程池、协程

    进程间通信 进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的. 进程队列queue 不同于线程queue,进程 ...

  5. 都2019年了,Java为什么还在坚持多线程不选择协程?

    都2019年了,Java为什么还在坚持多线程不选择协程? - 知乎 https://www.zhihu.com/question/332042250/answer/734051666

  6. python教程:使用 async 和 await 协程进行并发编程

    python 一直在进行并发编程的优化, 比较熟知的是使用 thread 模块多线程和 multiprocessing 多进程,后来慢慢引入基于 yield 关键字的协程. 而近几个版本,python ...

  7. Python 用队列实现多线程并发

    # Python queue队列,实现并发,在网站多线程推荐最后也一个例子,比这货简单,但是不够规范 # encoding: utf-8 __author__ = 'yeayee.com' # 由本站 ...

  8. python 并发编程 基于gevent模块 协程池 实现并发的套接字通信

    基于协程池 实现并发的套接字通信 客户端: from socket import * client = socket(AF_INET, SOCK_STREAM) client.connect(('12 ...

  9. portscaner 多线程、多协程并发端口扫描

    import socket,time,re,sys,os,threading import gevent from gevent import monkey monkey.patch_all() so ...

随机推荐

  1. 十一.keepalived高可用服务实践部署

    期中集群架构-第十一章-keepalived高可用集群章节======================================================================0 ...

  2. 《剑指offer》最小的k个数

    本题来自<剑指offer> 反转链表 题目: 思路: C++ Code: Python Code: 总结:

  3. js 随机生成颜色值

    function getRandomColor(){ var colorValue = [0,1,2,3,4,5,6,7,8,9,'a','b','c','d','e','f']; var s = & ...

  4. 传输层的端口与TCP标志中的URG和PSH位

    一.协议端口号的提出 运输层提供了进程间通信的能力(即端-端通信).但是不同的操作系统可能无法识别其他机器上的进程.为了用统一的方法对 TCP/IP体系的应用进程进行标志,使运行不同操作系统的计算机的 ...

  5. CSS之三个模型 盒子模型 轮廓模型 内外边距

    盒子模型 最终元素的总宽度计算公式是这样的: 总元素的宽度=宽度+左填充+右填充+左边框+右边框+左边距+右边距 元素的总高度最终计算公式是这样的: 总元素的高度=高度+顶部填充+底部填充+上边框+下 ...

  6. .net core2.x - 关于工作单元(UnitOfWork) 模式

    概要:在搭建框架,顺手说下写下,关于unitofwork,可能你理解了,可能你还不理解,可能与不可能不是重点,重点是感兴趣就看看吧. 1.工作单元(unitofowork)是什么(后面简写uow)? ...

  7. Prime Distance POJ - 2689 (数学 素数)

    The branch of mathematics called number theory is about properties of numbers. One of the areas that ...

  8. spark伪分布式的安装

    不依赖hadoop 百度分享安装包地址:http://pan.baidu.com/s/1dD4BcGT 点击打开链接 解压 并重命名: 进入spark100目录: 修改配置: Cd conf 配置单击 ...

  9. python 列表常用方法

    1.在列表末尾添加新的对象 li=[11,22,33,'aa','bb','cc'] li.append('dd') print(li) 2.清空列表 li=[11,22,33,'aa','bb',' ...

  10. python一个命令开启http服务器

    1.例如想共享文件在   E:python文件 打开cmd cd E: cd python文件 #进入要分享的文件夹 2.执行py脚本文件 python -m http.server 3.访问 本机i ...