day 35 协程与gil概念
博客链接:
http://www.cnblogs.com/linhaifeng/articles/7429894.html
今日概要:
- 1 生产者消费者模型(补充)
- 2 GIL(进程与线程的应用场景) *****
- 1\每一个cpython进程内都有一个GIL
- 2、GIL导致同一进程内的多个线程同一时间只能有一个运行
- 3、之所以有GIL,是因为Cpython的内存管理不是线程安全的
- 4、对于计算密集型用多进程,多IO密集型用多线程
- 3 死锁现象与递归锁 *
- #单线程实现并发
- 4 协程:
- 单线程下实现并发
- 5 IO模型
生产者消费者模型(补充版):
- # from multiprocessing import Process,Queue,JoinableQueue
- # import time,random,os
- #
- # def procducer(name,food,q):
- # for i in range(3):
- # res='%s%s' %(food,i)
- # time.sleep(0.5)
- # q.put(res)
- # print('%s make %s' %(name,res))
- #
- # def consumer(name,q):
- # while True:
- # res=q.get()
- # if res is None:
- # break
- # print('%s eat %s' %(name,res))
- # time.sleep(random.randint(2,3))
- #
- #
- # if __name__ == '__main__':
- # q=Queue()
- # p1=Process(target=procducer,args=('egon','dumpling',q,))
- # p2=Process(target=procducer,args=('rain','rice',q,))
- # p3=Process(target=procducer,args=('flower','dogfood',q,))
- # c1=Process(target=consumer,args=('alex',q,))
- # c2=Process(target=consumer,args=('wxx',q,))
- #
- # p1.start()
- # p2.start()
- # p3.start()
- # c1.start()
- # c2.start()
- #
- # p1.join()
- # p2.join()
- # p3.join()
- # q.put(None)
- # q.put(None)
- # print('host')
- from multiprocessing import Process,Queue,JoinableQueue
- import time,random,os
- def procducer(food,q):
- for i in range(3):
- res='%s%s' %(food,i)
- time.sleep(0.5)
- q.put(res)
- print('%s make %s' %(os.getpid(),res))
- q.join()
- def consumer(q):
- while True:
- res=q.get()
- print('%s eat %s' %(os.getpid(),res))
- time.sleep(random.randint(2,3))
- q.task_done()
- if __name__ == '__main__':
- q=JoinableQueue()
- p1=Process(target=procducer,args=('dumpling', q,))
- p2=Process(target=procducer,args=('rice', q,))
- p3=Process(target=procducer,args=('dog_food', q,))
- c1=Process(target=consumer,args=(q, ))
- c2=Process(target=consumer,args=(q, ))
- c1.daemon=True
- c2.daemon=True
- p1.start()
- p2.start()
- p3.start()
- c1.start()
- c2.start()
- p1.join()
- p2.join()
- p3.join()
- # producer has done, and 'q.join()' has already got all the data
- print('host', os.getpid())
gil:
- # from threading import Thread,Lock
- # import time
- # n=100
- # def task():
- # global n
- # mutext.acquire()
- # temp=n
- # time.sleep(0.1)
- # n=temp-1
- # mutext.release()
- # if __name__ == '__main__':
- # t_l=[]
- # mutext=Lock()
- # start=time.time()
- # for i in range(3):
- # t=Thread(target=task)
- # t_l.append(t)
- # t.start()
- #
- # for t in t_l:
- # t.join()
- # print(time.time()-start)
- # print(n)
- #
- #计算密集型:多进程效率高
- from multiprocessing import Process
- # from threading import Thread
- # import os,time
- # def work():
- # res=0
- # for i in range(10000000):
- # res*=i
- #
- # if __name__ == '__main__':
- # l=[]
- # print(os.cpu_count()) #本机为4核
- # start=time.time()
- # for i in range(4):
- # p=Process(target=work) #耗时run time is 0.8030457496643066
- # # p=Thread(target=work) #耗时run time is 2.134121894836426
- # l.append(p)
- # p.start()
- #
- # for p in l:
- # p.join()
- #
- # stop=time.time() #
- #
- # print('run time is %s' %(stop-start))
- from threading import Thread
- import os,time
- def work():
- time.sleep(2)
- if __name__ == '__main__':
- l=[]
- start=time.time()
- for i in range(100):
- # p=Process(target=work) #耗时run time is 4.881279230117798
- p=Thread(target=work) #耗时run time is 2.011115074157715
- l.append(p)
- p.start()
- for p in l:
- p.join()
- stop=time.time() #
- print('run time is %s' %(stop-start))
在计算密集型的程序中使用多进程,
在io密集型的程序中使用多线程
理解:
- # gil锁是一个概念性的知识点,它没有类似于class,类; def,函数;等等类似的具有标示性的东西,不具备可视性,但是是一个很重要的知识点需要理解,
# 需要明白它底层是如何执行的,它是已经被封装好的,明白后就能知道我们所学的进程并发和线程并发是在什么情况下使用的.
# 先说结论,计算密集型程序中使用多进程,效率更高;而在io密集型的程序中,使用多线程效率更高(单线程的并发效率更高,即协程.)
# 在cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程进行,无法利用多核优势
# 当我们在执行程序的时候,需要在Python解释器里面去运行程序,就类似于我们学计算机发展史的时候,那个时候工作人员需要去排队抢占计算机硬件资源,
# 轮流拿着自己的代码和写好的的程序去等着,就像现在我们在公司里面等着排队使用打印机的情况类似,那个时候的计算机很罕见,大家需要运行程序的时候
# 要等到轮到自己的时候才可以去把自己的程序放进去执行,那么在我们的系统内部也是这样的,我们的所有python代码都是我们写好后,在pycharm里面放着,
# 真正实现的底层是我们的python解释器在执行,但是解释器就类似于以前的老式计算机,它只能一个一个程序的运行,不能多个同时运行,
# 那么就涉及到先后顺序的问题,这里没有排队的概念,各个程序之间是竞争关系,谁抢到的了资源谁就先运行,要引用我们前几天学过的那个概念,并发的概念,
# 抢占cpu资源,CPU要一直运行下去,它不会一直让你一个程序去占着它,即便你抢到了它的使用权限,即便你的程序是一直在计算中,你的占用时间过长的话,
# 它一样会把你释放掉,把你的gil锁也给释放掉,这里的gil锁是一个什么样的概念呢,它本质就是互斥锁,即都是将并发运行变成串行,
# 以此来控制同一时间内共享数据只能被一个任务所修改,进而保证数据安全.所以我们的gil锁是为了保证数据的安全,这个是很重要的一点,
# 因为你并发的执行效率是很高的,一旦变成了串行就会大大降低,如果不是为了保证数据的安全性,是没有必要去牺牲执行效率的.这个是大前提.
# 分析:
# 我们有四个任务需要处理,处理方式肯定是要玩出并发的效果,解决方案可以是:
# 方案一:开启四个进程
# 方案二:一个进程下,开启四个线程
# 单核情况下,分析结果:
# 如果四个任务是计算密集型,没有多核来并行计算,方案一徒增了创建进程的开销,方案二胜
# 如果四个任务是I / O密集型,方案一创建进程的开销大,且进程的切换速度远不如线程,方案二胜
# 多核情况下,分析结果:
# 如果四个任务是计算密集型,多核意味着并行计算,在python中一个进程中同一时刻只有一个线程执行用不上多核,方案一胜
# 如果四个任务是I / O密集型,再多的核也解决不了I / O问题,方案二胜
# 结论:现在的计算机基本上都是多核,python对于计算密集型的任务开多线程的效率并不能带来多大性能上的提升,甚至不如串行(没有大量切换),
# 但是,对于IO密集型的任务效率还是有显著提升的。
# 应用:
#
# 多线程用于IO密集型,如socket,爬虫,web
# 多进程用于计算密集型,如金融分析- 死锁现象与递归锁:
- from threading import Thread,Lock,RLock
- import time
- # mutexA=mutexB=Lock()
- mutexA=mutexB=RLock()
- class MyThread(Thread):
- def run(self):
- self.f1()
- self.f2()
- def f1(self):
- mutexA.acquire()
- print('%s 拿到A锁' %self.name)
- mutexB.acquire()
- print('%s 拿到B锁' %self.name)
- mutexB.release()
- mutexA.release()
- def f2(self):
- mutexB.acquire()
- print('%s 拿到B锁' % self.name)
- time.sleep(0.1)
- mutexA.acquire()
- print('%s 拿到A锁' % self.name)
- mutexA.release()
- mutexB.release()
- if __name__ == '__main__':
- for i in range(10):
- t=MyThread()
- t.start()
协程:
- # import time
- # def consumer(res):
- # '''任务1:接收数据,处理数据'''
- # pass
- #
- # def producer():
- # '''任务2:生产数据'''
- # res=[]
- # for i in range(100000000):
- # res.append(i)
- # return res
- #
- # start=time.time()
- # #串行执行
- # res=producer()
- # consumer(res)
- # stop=time.time()
- # print(stop-start) #
- import time
- def consumer():
- '''任务1:接收数据,处理数据'''
- while True:
- x=yield
- print('consumer')
- def producer():
- '''任务2:生产数据'''
- g=consumer()
- next(g)
- for i in range(100000000):
- print('producer')
- time.sleep(6)
- g.send(i)
- start=time.time()
- #基于yield保存状态,实现两个任务直接来回切换,即并发的效果
- #PS:如果每个任务中都加上打印,那么明显地看到两个任务的打印是你一次我一次,即并发执行的.
- producer()
- stop=time.time()
- print(stop-start) #1.2250702381134033
- #pip3 install gevent
- #1、切换+保存状态
- #2 检测IO,实现遇到IO切换
- from gevent import monkey;monkey.patch_all()
- import gevent
- import time
- def eat(name):
- print('%s eat 1' %name)
- time.sleep(2)
- print('%s eat 2' %name)
- def play(name):
- print('%s play 1' %name)
- time.sleep(3)
- print('%s play 2' %name)
- g1=gevent.spawn(eat,'alex')
- g2=gevent.spawn(play,'egon')
- g1.join()
- g2.join()
day 35 协程与gil概念的更多相关文章
- 进程、线程、协程和GIL(二)
上一篇博客讲了进程.线程.协程和GIL的基本概念,这篇我们来说说在以下三点: 1> python中使用threading库来创建线程的两种方式 2> 使用Event对消来判断线程是否已启动 ...
- 线程、进程、协程和GIL(一)
参考链接:https://www.cnblogs.com/alex3714/articles/5230609.html https://www.cnblogs.com/work115/p/562027 ...
- 线程、进程、协程和GIL(三)
上一篇文章介绍了:创建线程的两种方式.Event对象判断线程是否启动.利用信号量控制线程并发. 博客链接:线程.进程.协程和GIL(二) 这一篇来说说线程间通信的那些事儿: 一个线程向另一个线程发送数 ...
- day 35 协程 IO多路复用
0.基于socket发送Http请求 import socket import requests # 方式一 ret = requests.get('https://www.baidu.com/s?w ...
- python基础(35):协程
1. 前言 之前我们学习了线程.进程的概念,了解了在操作系统中进程是资源分配的最小单位,线程是CPU调度的最小单位.按道理来说我们已经算是把cpu的利用率提高很多了.但是我们知道无论是创建多进程还是创 ...
- Kotlin协程重要概念详解【纯理论】
在之前对Kotlin的反射进行了详细的学习,接下来进入一个全新的篇章,就是关于Koltin的协程[coroutine],在正式撸码之前先对它有一个全面理论化的了解: 协程的定义: 协和通过将复杂性放入 ...
- 15.python并发编程(线程--进程--协程)
一.进程:1.定义:进程最小的资源单位,本质就是一个程序在一个数据集上的一次动态执行(运行)的过程2.组成:进程一般由程序,数据集,进程控制三部分组成:(1)程序:用来描述进程要完成哪些功能以及如何完 ...
- python笔记-10(socket提升、paramiko、线程、进程、协程、同步IO、异步IO)
一.socket提升 1.熟悉socket.socket()中的省略部分 socket.socket(AF.INET,socket.SOCK_STREAM) 2.send与recv发送大文件时对于黏包 ...
- Python协程理解——基于爬虫举例
当前代码在工作当中没有太大的含义,但是对于大家理解协程的基础概念是相当有好处的协程最直接的可以理解为程序当中一个没有返回的功能块儿我们之前有学过多线程,所谓的多线程不论是异步并发,还是并发强调的时候将 ...
随机推荐
- .NET NPOI操作Excel 让单元格的内容换行
HSSFWorkbook workbook = new HSSFWorkbook(); // 工作簿 ISheet sheet = workbook.CreateSheet("会员列表&qu ...
- python-基于UDP通信的套接字,socketserver模块的使用
一.基于UDP协议通信的套接字 udp是没有链接的,所以先启动哪一端都不会报错 import socket server=socket.socket(socket.AF_INET,socket.SOC ...
- 信息摘要算法之二:SHA1算法分析及实现
SHA算法,即安全散列算法(Secure Hash Algorithm)是一种与MD5同源的数据加密算法,该算法经过加密专家多年来的发展和改进已日益完善,现在已成为公认的最安全的散列算法之一,并被广泛 ...
- Pl/SQL 编程
Pl/SQL 编程 一:前言 二:Pl/Sql 概述 二 —— 1: Pl/Sql块结构 [declare] --声明部分,可选 begin --执行部分,必须 [exception] -- ...
- 《JavaWeb从入门到精通》(明日科技,清华大学出版社)
<JavaWeb从入门到精通>(明日科技,清华大学出版社)
- sticky footer 模板
http://www.w3cplus.com/blog/tags/136.html http://www.w3cplus.com/css/css-sticky-foot-at-bottom-of-th ...
- 暑假里的第八篇Java
日期:2018.9.1 博客期:008 星期六 这几天刚到学校,Java方面写的少了!目前在做老师头放假前发布的那一套题目,就是哪个Java程序测试卷.至于自己能不能都做出来我自己心里十分清楚!今天就 ...
- VGG-Net
论文下载 源码GitHub 目的 这篇文章是以比赛为目的——解决ImageNet中的1000类图像分类和定位问题.在此过程中,作者做了六组实验,对应6个不同的网络模型,这六个网络深度逐渐递增的同时,也 ...
- python3 HTMLTestRunner.py
""" A TestRunner for use with the Python unit testing framework. It generates a HTML ...
- C++ Primer 笔记——const 限定符
1.因为const对象一旦创建后其值就不能再改变,所以const对象必须初始化. 2.默认情况下const对象只在文件内有效,如果想在多个文件之间共享const对象,必须在变量的定义之前添加exter ...