博客链接:

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. CXF使用

    一.服务端: 1.web.xml配置 <servlet> <servlet-name>cxf</servlet-name> <servlet-class> ...

  2. python-迭代器、生成器、内置函数及面向过程编程

    一.迭代器 迭代器是迭代取值的工具,迭代是一个重复的过程,每一次重复都是基于上一次的结果而来的. 为什么要用迭代器呢? 1.可以不依赖索引取值 2.同一时刻在内存中只有一个值,不会过多的占用内存 如何 ...

  3. 设置 Confluence 6 日志

    Confluence 使用的是 Apache's log4j 日志服务.能够允许管理员通过编辑配置文件来控制日志的表现和日志输出文件.在系统中有 6 个日志输出级别,请参考 log4j logging ...

  4. selenium+python之 辨识alert、window以及操作

    1.分辨 首先区别下alert.window和伪装对话框: alert,浏览器弹出框,一般是用来确认某些操作.输入简单的text或用户名.密码等,根据浏览器的不同,弹出框的样式也不一样,不过都是很简单 ...

  5. cf441 f组合数。。单调指针

    e没学过做不出来.. 处理合法的区间很麻烦,但是处理非合法的区间很容易 答案就是所有的取法-不合法的区间 这题一定要双边界推进处理!!!! 一开始用单边界向右推进,结果后来发现错了,拿样例1就可以证明 ...

  6. hiho1460 rmq模板题

    好久没做rmq的题了,今天写了一遍,感觉打表有点像区间dp /* 给定长为n的字符串,要求在字符串中选择k个字符, 选择的子系列字典序最小 因为选择k个字符,那么就是去掉n-k个字符 那么[1,n-k ...

  7. shell 脚本加密

    日常编写shell脚本时会写一些账号和密码写入脚本内,但是不希望泄露账号密码,所以对shell脚本进行加密变成可执行文件. 主要使用 shc 对 Linux shell 脚本加密,shc是一个专业的加 ...

  8. Loadrunner11.0 录制手机App脚本的方法一

    使用Loadrunner录制手机终端App脚本 1. 说明 目前手机APP上的功能日益丰富,对手机应用功能的性能测试需求也越来越多.公司比较抠门没有花钱买Loadrunner,可怜我们工作中一直用的破 ...

  9. Duplicate 复制数据库 搭建Dataguard

    1 操作系统环境 此处隐藏具体信息 System IP-address db_name db_version Comment         Target DB         Auxiliary D ...

  10. tensorflow:验证码的识别(中)

    三.训练识别模型 首先先拷贝一个nets文件夹,主要使用的是文件夹下的两个文件nets_factory.py.alexnet.py,用于导入训练使用的网络alexnet. nets_factory.p ...