并发编程

基本概念的区分:

  • 并发
    只有一个CPU,多个程序在一个CPU上轮流执行,宏观上多个进程并发执行,但微观上依旧是串行

  • 并行
    有多个CPU,多个程序在多个CPU上同时执行。

  • 进程
    计算机中最小的资源分配单位,占用资源,数据隔离,需要操作系统进行调度,每一个程序就是一个进程,其中使用pid作为进程间的唯一标识。

  • 线程
    线程必须存在于进程中,不能独立存在,不占用资源,数据共享,是能够被计算机独立运行和独立调度的最小单位 ,一个进程中可以有多个线程,但至少有一个

  • 同步
    在事件A执行过程中发起事件B,只有B结束,A才能继续执行,需要等结果

  • 异步
    在事件A执行过程中发起事件B,不需要B结束,A可以继续执行,不需要等结果

进程并发:

#全局执行
from multiprocessing import Process #多进程模块
import osdef fun(name,*args):print(name,os.getpid(),os.getppid())print('全局执行')
if __name__ == '__main__':#因此此处也终止了死循环#只在主进程下执行的代码print('main:',os.getpid(), os.getppid())  #整个程序的主进程,和父进程print('只在主进程执行')p = list()proc1 = Process(target=fun,args=("lisi",)) #传参print('开启子进程lisi')proc1.start()         #在当前的主进程又创建了一个子进程,当前进程既为子进程又为父进程p.append(proc1)proc2 = Process(target=fun, args=('wangwu',))  # 传参print('开启子进程wangwu')proc2.start()   #异步非阻塞状态# p.terminate()#强制结束一个子进程# p.daemon =True #变为守护进程,直到主进程的代码结束,才结束p.append(proc2)for i in p: i.join() #同步阻塞;直到proc1,proc2进程都执行完,才继续执行print('全部子进程执行完毕')

执行结果:

全局执行
main: 19028 10944
只在主进程执行
开启子进程lisi
开启子进程wangwu
全局执行
全局执行
lisi 7820 19028
wangwu 20068 19028
全部子进程执行完毕

上面使用函数的方法创建进程,还可以用类的方法创建进程

from multiprocessing import Process #多进程模块
class P(Process):#继承自Processdef __init__(self,a):#传参super().__init__()self.a = adef run(self):#必须重写run方法,类似于socketserver中必须重写handel方法print('way 2 %s'%self.a)
if __name__ == '__main__':p = P('zhangda')p.start()print(p.name,p.is_alive())#进程的名字,是否存活

执行结果:

P-1 True
way 2 zhangda
  • 进程间的通信(ICP inter process communication)
    – 基于文件通信:同一台机器上的多个进程间通信
    如:socket基于文件级别的进程间数据通信(Queue队列,pipe管道)
    – 基于网络通信:一台或多台机器上的多个进程间的通信
    借助一些第三方工具,消息中间件,如:redis,kafka等
from multiprocessing import Process,Queue
def func(q):q.put('hello')def producter(q):for i in range(10):q.put(i)#放一个def consumer(q):for i in range(10):print(q.get(),end='-')#取一个if __name__ == '__main__':q = Queue()  #共享数据的队列proc1 =  Process(target=func,args=(q,))proc1.daemon = Trueproc1.start()#开启1print(q.get())proc2 = Process(target=producter, args=(q,))proc2.start()#开启2proc3 = Process(target=consumer, args=(q,))proc3.start()#开启3

执行结果:

hello
0-1-2-3-4-5-6-7-8-9-

  • 多线程
    主线程结束,进程就会结束,守护线程随着主线程结束而结束,但如果主线程代码结束后还有子线程,会继续守护其他子线程。
    守护进程和守护线程的区别:守护进程需要主进程来回收资源,其他子线程–》主线程结束–》守护进程结束–》主进程结束–》父进程回收主进程所有资源–》守护线程被回收。

线程锁-单例模式:防止不必要的数据共享,带来数据不安全
其余操作线程与进程相似

from threading import Thread,current_thread,enumerate,active_count
from multiprocessing import Process,current_process
import time
# enumerate所有活着线程的对象
# active_count所有活着线程的数量class A:#线程的单例模式,保护数据__instance = Nonefrom threading import Locklock = Lock()def __new__(cls,*args, **kwargs):with cls.lock:#不加锁会导致线程并发,不同步,重复创建空间,三个不同的cls.__instanceif not cls.__instance:time.sleep(0.01)cls.__instance=super().__new__(cls)print(cls.__instance,'new')return cls.__instancedef func(a):print('当前线程id:%d\n'%current_thread().ident)a = A()print(a)if __name__ == '__main__':for i in range(3):t= Thread(target=func,args=(10,))t.start()print(enumerate(),active_count())

执行结果

当前线程id:4560当前线程id:16864当前线程id:14628[<_MainThread(MainThread, started 20764)>, <Thread(Thread-1, started 4560)>, <Thread(Thread-2, started 16864)>, <Thread(Thread-3, started 14628)>] 4
<__main__.A object at 0x000001E6605D8130> new
<__main__.A object at 0x000001E6605D8130>
<__main__.A object at 0x000001E6605D8130>
<__main__.A object at 0x000001E6605D8130>
  • 一定会发生数据不安全的情况
  1. 数据共享,且异步
  2. +=,-=,*=,/=,赋值,=计算后,数据不安全
  3. if,while不在同一个线程中完成

线程间的数据安全共享的容器

from queue import Empty,Queue,LifoQueue,PriorityQueue#LifoQueue  先进后出,栈类型# Queue 先进先出,队列类型# PriorityQueue,优先级队列#Empty  queue的错误类型q = Queue()q.put(1)q.put_nowait(1)#易丢失数据print('queue:%d'%q.get())try:print(q.get_nowait())except Empty:print('no data')l = LifoQueue()l.put(10)l.put(20)print('lifoqueue:%d'%l.get_nowait())pro = PriorityQueue()#进行了排序pro.put(2222222)pro.put(1111111)print('prio:%d'%pro.get()

执行结果

queue:1
1
lifoqueue:20
prio:1111111
  • 递归锁与互斥锁(Rlock,Lock)


  • 要在程序开始,还没有提交任务的时候就预先创建几个进程或者进程放在池子里。提前开好,直接使用,限制额度,整体关闭。

进程池:用于高计算场景(无io(文件操作,数据库操作,网络操作,input等)) cpu_count<num<cpu_count*2
线程池:一般根据io比例进行定制,cpu_count*5

进程池与线程池相似

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
from threading import  current_thread
import time
def func(a):print(current_thread().ident)time.sleep(1)#阻塞return adef print_ret(ret):print(ret.result())if __name__ == '__main__':tp = ThreadPoolExecutor(4)#四个一组完成并发for i in range(5):ret =tp.submit(func,i)#任务提交到池,让池中的线程替你完成# print(ret.result)   #future未来对象,造成同步阻塞,顺序轮流执行ret.add_done_callback(print_ret)#回调函数,造成异步阻塞,先返回先执行# 或者写成下面# ret =tp.map(func,range(10))#可迭代参数# for i in ret:#     print(i)

执行结果

12472
3208
9412
7588
1
3208
0
2
3
4
  • 协程
    操作系统不可见,本质还是一条线程,只是多个任务在一条线程上来回切换,以规避io操作带来的时间损失,达到一条线程上io操作降到最低,充分利用CPU的目的,但线程的所有切换都基于用户,用户可以感知到的io才会进行切换,所以io操作的时间间隔比线程长。

切换并规避io的模块:

  1. gevent = 利用greenlet 底层模块实现切换+自动规避io
  2. asyncio=利用yield 底层语法实现切换+i自动规避io

from gevent import monkey
monkey.patch_all()
import time
import geventdef func():print('start')time.sleep(1)print('end')g1 = gevent.spawn(func)
g2 = gevent.spawn(func)
g3 = gevent.spawn(func)
gevent.joinall([g1,g2,g2])
g1.join()
print('*'*10)import asyncioasync def begin():print('start')await asyncio.sleep(1)  #可能会报错的地方,从这里切走print('end')loop = asyncio.get_event_loop() #事件循环
loop.run_until_complete(begin())

执行结果

start
start
start
end
end
end
**********
start
end

Python 并发编程--进程,线程,协程相关推荐

  1. 《转载》Python并发编程之线程池/进程池--concurrent.futures模块

    本文转载自 Python并发编程之线程池/进程池--concurrent.futures模块 一.关于concurrent.futures模块 Python标准库为我们提供了threading和mul ...

  2. Python之进程+线程+协程(异步、selectors模块、阻塞、非阻塞IO)

    文章目录 一.IO多路复用 二.selectors模块 本篇文字是关于IO多路复用的更深入一步的总结,上一篇 Python之进程+线程+协程(事件驱动模型.IO多路复用.select与epoll)对I ...

  3. linux的进程/线程/协程系列5:协程的发展复兴与实现现状

    协程的发展复兴与实现现状 前言 本篇摘要: 1. 协同制的发展史 1.1 协同工作制的提出 1.2 自顶向下,无需协同 1.3 协同式思想的应用 2. 协程的复兴 2.1 高并发带来的问题 2.2 制 ...

  4. Linux的进程/线程/协程系列4:进程知识深入总结:上篇

    Linux的进程/线程/协程系列4:进程/线程相关知识总结 前言 本篇摘要: 1. 进程基础知识 1.1 串行/并行与并发 1.2 临界资源与共享资源 1.3 同步/异步与互斥 1.4 进程控制原语 ...

  5. linux的进程/线程/协程系列1:进程到协程的演化

    linux的进程/线程/协程系列1:进程到协程的演化 前言 摘要: 1. 一些历史:批处理时代 2. 现代操作系统启动过程 3. 进程(process)的出现 4. 线程(thread)与线程池 5. ...

  6. linux的进程/线程/协程系列3:查看linux内核源码——vim+ctags/find+grep

    linux的进程/线程/协程系列3:查看linux内核源码--vim+ctags/find+grep 前言 摘要: 1. 下载linux内核源码 2. 打标签方法:vim+ctags 2.1 安装vi ...

  7. 进程 线程 协程 各自的概念以及三者的对比分析

    文章目录 1 进程 2 线程 3 进程和线程的区别和联系 3.1 区别 3.2 联系 4 举例说明进程和线程的区别 5 进程/线程之间的亲缘性 6 协程 线程(执行一个函数)和协程的区别和联系 协程和 ...

  8. 简要说明__python3中的进程/线程/协程

    多任务可以充分利用系统资源,极大提升程序运行效率,多任务的实现往往与 多线程,多进程,多协程有关 稳定性: 进程 > 线程 > 协程 系统资源占用量:进程 > 线程 > 协程 ...

  9. Python并发编程之线程池/进程池

    引言 Python标准库为我们提供了threading和multiprocessing模块编写相应的多线程/多进程代码,但是当项目达到一定的规模,频繁创建/销毁进程或者线程是非常消耗资源的,这个时候我 ...

  10. 面试官:换人!他连进程线程协程这几个特点都说不出

    前言 很早之前就在构思这篇文章的主题,进程线程可以说是操作系统基础,看过很多关于这方面知识的文章都是纯理论讲述,编程新手有些难以直接服用. 于是写下这篇文章,用图解的形式带你学习和掌握进程.线程.协程 ...

最新文章

  1. mac composer 使用
  2. Quartz-Trigger详解
  3. C#通过SMTP发送邮件代码示例
  4. java读取、生成图片
  5. web开发中的JAVA字符转码
  6. Linux driver 板级文件跟踪一般方法
  7. excel函数公式html文档,15个常用excel函数公式
  8. MTK手机烧录与调试
  9. 移动端一倍图,二倍图尺寸
  10. Python之生成器练习
  11. android手机品牌排行,智能手机品牌排行榜2019前十名
  12. 李华明Himi 游戏开发
  13. 小布语音下载安装_oppo语音助手小布小冰安装包app
  14. ESLint 格式化程序
  15. Python实现奇数阶幻方(不用numpy)
  16. 招聘网站数百万条敏感数据泄露,简历、身份证扫描件统统曝光
  17. Webpack--模块热替换(HMR)
  18. python画太极八卦图_CAD怎么画出八卦图? cad画完整太极八卦图的教程
  19. (thinkPHP)入门
  20. 好东西下载Download

热门文章

  1. 微信三级分销系统有哪些内容
  2. 简易五子棋(包含开始、双人对战、简易AI、悔棋、认输、判断输赢)不含禁手
  3. IDM下载百度网盘文件,获取百度网盘文件url地址,破解
  4. Linux环境中ElasticSearch启动时常见错误、解决
  5. 【Auto.js 】Android 脚本软件 简要介绍及学习资料
  6. 【资源】部分稀有资源
  7. java之详解坦克大战_Java之详解坦克大战游戏(一)
  8. ftrace和tracepoint简单使用
  9. 安卓系统USB产品芯片使用推荐
  10. 如何查询尼斯分类商品项目