博客链接:

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概念的更多相关文章

  1. 进程、线程、协程和GIL(二)

    上一篇博客讲了进程.线程.协程和GIL的基本概念,这篇我们来说说在以下三点: 1> python中使用threading库来创建线程的两种方式 2> 使用Event对消来判断线程是否已启动 ...

  2. 线程、进程、协程和GIL(一)

    参考链接:https://www.cnblogs.com/alex3714/articles/5230609.html https://www.cnblogs.com/work115/p/562027 ...

  3. 线程、进程、协程和GIL(三)

    上一篇文章介绍了:创建线程的两种方式.Event对象判断线程是否启动.利用信号量控制线程并发. 博客链接:线程.进程.协程和GIL(二) 这一篇来说说线程间通信的那些事儿: 一个线程向另一个线程发送数 ...

  4. day 35 协程 IO多路复用

    0.基于socket发送Http请求 import socket import requests # 方式一 ret = requests.get('https://www.baidu.com/s?w ...

  5. python基础(35):协程

    1. 前言 之前我们学习了线程.进程的概念,了解了在操作系统中进程是资源分配的最小单位,线程是CPU调度的最小单位.按道理来说我们已经算是把cpu的利用率提高很多了.但是我们知道无论是创建多进程还是创 ...

  6. Kotlin协程重要概念详解【纯理论】

    在之前对Kotlin的反射进行了详细的学习,接下来进入一个全新的篇章,就是关于Koltin的协程[coroutine],在正式撸码之前先对它有一个全面理论化的了解: 协程的定义: 协和通过将复杂性放入 ...

  7. 15.python并发编程(线程--进程--协程)

    一.进程:1.定义:进程最小的资源单位,本质就是一个程序在一个数据集上的一次动态执行(运行)的过程2.组成:进程一般由程序,数据集,进程控制三部分组成:(1)程序:用来描述进程要完成哪些功能以及如何完 ...

  8. python笔记-10(socket提升、paramiko、线程、进程、协程、同步IO、异步IO)

    一.socket提升 1.熟悉socket.socket()中的省略部分 socket.socket(AF.INET,socket.SOCK_STREAM) 2.send与recv发送大文件时对于黏包 ...

  9. Python协程理解——基于爬虫举例

    当前代码在工作当中没有太大的含义,但是对于大家理解协程的基础概念是相当有好处的协程最直接的可以理解为程序当中一个没有返回的功能块儿我们之前有学过多线程,所谓的多线程不论是异步并发,还是并发强调的时候将 ...

随机推荐

  1. 数据库-mysql-DDL-表记录操作

  2. linux中ping带时间及打印内容到文件

    ping命令就不多说了,-i是时间间隔,-c是ping的次数 这种是每隔30秒ping一次,并在后面显示时间: ping 192.168.30.123 -i 30 | awk '{ print $0& ...

  3. cmder 神器 +curl

    cmder 神器 https://www.jianshu.com/p/7a706c0a3411 curl https://www.cnblogs.com/zhuzhenwei918/p/6781314 ...

  4. Oracle从入门到精通(详细) 明日科技

  5. ?:,reverse,vector的基本小结

    #include <cstdio> //此代码为网上所复制 #include <iostream> #include <string> #include <s ...

  6. Layers Of Caffe

    本文试图描述构建一个网络结构的layers,可以用prototxt脚本直接写,也可以用python接口实现. 最简单的神经网络包含但不限于以下四部分: 数据层(Data): Data.ImageDat ...

  7. cf919D 线性dp+拓扑排序

    /* 给定一张有向图,图上每个结点都有一个字符,现在要求出一条路径,要使路径上某字符出现的次数最多 如果有环,输出-1即可 拓扑排序+dp dp[i][26]表示排序到结点i时26个字符出现的次数 在 ...

  8. js中json对象数组按对象属性排序(sort方法)---2(根据拼音排序汉字和排序英文)

    本例主要实现 中文汉字按拼音排序的方法和英文按照首字母排序的方法. 要排序的数据: //要排序的数据 let data = [ {chinese: '蔡司', english: 'Chase'}, { ...

  9. Python继承、方法重写

    继承 在编写类时,并不是每次都要从空白开始.当要编写的类和另一个已经存在的类之间存在一定的继承关系时,就可以通过继承来达到代码重用的目的,提高开发效率. class one(): "&quo ...

  10. C++ gethostname()

    使用“gethostname();”获取计算机名,先看源码: 在Code::Blocks 16.01中,设置project的Build options...,Debug > Linker set ...