python进阶——进程/线程/协程
1 python线程
python中Threading模块用于提供线程相关的操作,线程是应用程序中执行的最小单元。
#!/usr/bin/env python
# -*- coding:utf-8 -*- import threading
import time def show(arg):
time.sleep(1)
print 'thread'+str(arg) for i in range(10):
#调用构造函数,实例化对象,第1个参数是线程执行的函数,第2个参数是函数参数
t = threading.Thread(target=show, args=(i,))
#线程准备就绪,等待CPU调度
t.start() print 'main thread stop'
上述代码创建了10个“前台”线程,然后控制器就交给了CPU,CPU根据指定算法进行调度,分片执行指令。
为什么是分片执行?
python中有一个GIL(Global Interpreter Lock 全局解释器锁 ),即在同一时刻只有一个线程在执行,底层自动进行上下文切换。一个应用程序一般只存在一个进程,在进程中存在一个线程,线程是应用程序的最小执行单元。如果该进程中存在多个线程,其实也是串行执行的,即相当于在每个进程的出口,多个线程任务请求cpu调度,因为GIL的原因,只有一个线程能够被调度,所以单个进程不管有多少线程只能调度一个cpu。
线程模块threading中的方法:
start 线程准备就绪,等待CPU调度
setName 为线程设置名称
getName 获取线程名称
setDaemon 设置为后台线程或前台线程(默认)
如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均停止
如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止
join 逐个执行每个线程,执行完毕后继续往下执行,该方法使得多线程变得无意义
run 线程被cpu调度后执行Thread类对象的run方法
2 线程锁
由于线程是随机调度,可能某个线程只执行一部分代码,cpu就被调度执行其它线程了。下面是例子:
#!/usr/bin/env python
# -*- coding:utf-8 -*- import threading
import time gl_num = 0 def show(arg):
global gl_num
time.sleep(1)
gl_num +=1
print gl_num for i in range(10):
t = threading.Thread(target=show, args=(i,))
t.start() print 'main thread stop'
没加线程锁代码
执行结果
#!/usr/bin/env python
#coding:utf-8 import threading
import time gl_num = 0 lock = threading.RLock() #实例化线程锁 def Func():
lock.acquire() #获取线程锁
global gl_num
gl_num +=1
time.sleep(1)
print gl_num
lock.release() #释放线程锁,这里注意,在使用线程锁的时候不能把锁,写在代码中,否则会造成阻塞,看起来“像”单线程 for i in range(10):
t = threading.Thread(target=Func)
t.start()
加线程锁后代码
执行结果
3 event
python线程的事件用于主线程控制其他线程的执行,事件主要提供了三个方法 set、wait、clear。
事件处理的机制:全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果“Flag”值为True,那么event.wait 方法时便不再阻塞。
- clear:将“Flag”设置为False
- set:将“Flag”设置为True
#!/usr/bin/env python
# -*- coding:utf-8 -*- import threading def do(event):
print 'start'
event.wait() #执行event对象wait方法,然后他们停下来,等待“Flag”为True
print 'execute' event_obj = threading.Event() #创建事件的对象 for i in range(10):
t = threading.Thread(target=do, args=(event_obj,)) #event对象传给每个线程
t.start() event_obj.clear() #设置"Flag"为Flase inp = raw_input('input:')
if inp == 'true':
event_obj.set()
event事件代码
4 python进程
from multiprocessing import Process def foo(i):
print 'say hi',i for i in range(10):
p = Process(target=foo,args=(i,))
p.start()
多进程代码
注意:由于进程之间的数据需要各自持有一份,所以创建进程需要非常大的开销。并且python不能在Windows下创建进程!在使用多进程的时候,最好是创建和CPU核数相等进程数,默认进程之间相互独立,如果想让进程之间数据共享,就得有个特殊的数据结构,这个数据结构就可以理解为他有穿墙的功能。
进程数据共享
进程各自持有一份数据,默认无法共享数据
#!/usr/bin/env python
#coding:utf-8 from multiprocessing import Process
from multiprocessing import Manager import time li = [] def foo(i):
li.append(i)
print 'say hi',li for i in range(10):
p = Process(target=foo,args=(i,))
p.start() print 'ending',li
默认无法共享数据
使用特殊的数据结构来实现进程共享数据
默认进程之间是相互独立的,如果想让进程之间共享数据,那么在python中需要借助特殊的数据结构 第1种方法:
#通过特殊的数据结构Array from multiprocessing import Process
from multiprocessing import Array #创建1个只包含数字类型的Array,可以看做是”类型与列表“组合的数据结构
temp = Array('i', [11,22,33,44]) #其中i是数据类型,这里i表示整型,后面就是python中的列表 def Foo(i):
temp[i] = 100+i
for item in temp:
print i,'----->',item for i in range(2):
p = Process(target=Foo,args=(i,))
p.start() 第二种方法:
#通过特殊的数据结构manage.dict()共享数据 from multiprocessing import Process
from multiprocessing import Manager #创建Manager对象manage
manage = Manager()
dic = manage.dict() #创建字典对象dic,这里的字典和python中字典使用方法一样! def Foo(i):
dic[i] = 100+i
print dic.values() for i in range(2):
p = Process(target=Foo,args=(i,))
p.start()
p.join() #注意此处调用join方法,否则报错
两种特殊数据结构实现进程间数据共享
#!/usr/bin/env python
# -*- coding:utf-8 -*- from multiprocessing import Process
from multiprocessing import Array
from multiprocessing import RLock def Foo(lock,temp,i):
lock.acquire() #获取锁
temp[0] = 100+i
for item in temp:
print i,'--->',item
lock.release() #释放锁 lock = RLock() #生成锁对象
temp = Array('i', [11, 22, 33, 44]) #用特殊数据结构Array实现进程间共享数据 for i in range(20):
p = Process(target=Foo,args=(lock,temp,i,))
p.start()
进程锁
5 进程池
进程池内部维护一个进程序列,当使用时去进程池中获取一个进程,如果进程池序列中没有可供使用的进程,那么程序就会等待,直到进程池中有可用进程为止。
进程池中有两个方法:apply 阻塞 apply_async 非阻塞
#!/usr/bin/env python
# -*- coding:utf-8 -*- from multiprocessing import Process
from multiprocessing import Pool
import time def Foo(i):
time.sleep(2)
return i+100 def Bar(arg):
print arg pool = Pool(5) #创建一个进程池
#print pool.apply(Foo,(1,))#向进程池申请一个进程去执行Foo方法
#print pool.apply_async(func =Foo, args=(1,)).get() #获取返回值 for i in range(10):
#Foo函数的执行结果返回,作为Bar函数的参数
pool.apply_async(func=Foo, args=(i,),callback=Bar) print 'end'
pool.close()
pool.join()#进程池中进程执行完毕后终止程序,如果不调用jion方法,那么主进程执行完后程序直接关闭。
进程池
6 协程
线程和进程都是由操作系统开辟的,即python进程和线程内部都是调用操作系统的API,这样系统的开销比较大。而对于协程,它是由程序员开辟的,由程序员进行控制,不需要调用操作系统的API。对于线程和进程来说,它是由CPU调度的,而协程完全由程序员控制,不需要CPU调度。
协程的意义:对于多线程,CPU通过切片的方式来执行线程,线程切换时需要耗时(保存状态,下次继续)。协程则存在于线程中,在线程中控制代码块的执行顺序。
适用场景:在其他语言中,协程存在的意义不大,因为多线程可以解决I/O操作问题,但是python存在GIL(Global Interpreter Lock 全局解释器锁 ),在同一时刻只能执行1个线程,所以,如果一个线程里I/O操作特别多,协程就比较适用,当进行IO操作时,可以调度执行其它代码段,避免由于IO操作时的阻塞导致CPU闲置
#!/usr/bin/env python
# -*- coding:utf-8 -*- #导入协程模块greenlet
from greenlet import greenlet def test1():
print 12
gr2.switch() #切换到协程2
print 34 #协程2切换回来之后,执行此语句,和yield类似
gr2.switch() #切换到协程2 def test2():
print 56
gr1.switch() #切换到协程1
print 78 gr1 = greenlet(test1) #创建了一个协程对象
gr2 = greenlet(test2) gr1.switch() #执行协程1
实例
协程:把一个线程分成了多个协程,达到控制代码段的执行顺序,协程就是对线程的分片。上面的实例需要手动控制协程的执行顺序,因为greenlet需要人为的指定调度顺序的,而gevent对greenlet进行了封装,达到遇到IO操作自动切换。实例如下
from gevent import monkey; monkey.patch_all()
import gevent
import urllib2 def f(url):
print('GET: %s' % url)
resp = urllib2.urlopen(url) #当遇到I/O操作时,会调用协程操作,程序继续执行,协程就阻塞等待数据的返回
data = resp.read()
print('%d bytes received from %s.' % (len(data), url)) gevent.joinall([
gevent.spawn(f, 'https://www.python.org/'), #f是调用的方法,其后的是传递的参数
gevent.spawn(f, 'https://www.yahoo.com/'),
gevent.spawn(f, 'https://github.com/'),
gevent实例
参考资料:
http://www.cnblogs.com/wupeiqi/articles/5040827.html
http://www.cnblogs.com/luotianshuai/p/5111587.html
http://www.cnblogs.com/kaituorensheng/p/4445418.html(进程池)
python进阶——进程/线程/协程的更多相关文章
- python的进程/线程/协程
1.python的多线程 多线程就是在同一时刻执行多个不同的程序,然而python中的多线程并不能真正的实现并行,这是由于cpython解释器中的GIL(全局解释器锁)捣的鬼,这把锁保证了同一时刻只有 ...
- Python中进程线程协程小结
进程与线程的概念 进程 程序仅仅只是一堆代码而已,而进程指的是程序的运行过程.需要强调的是:同一个程序执行两次,那也是两个进程. 进程:资源管理单位(容器). 线程:最小执行单位,管理线程的是进程. ...
- Python并发编程系列之常用概念剖析:并行 串行 并发 同步 异步 阻塞 非阻塞 进程 线程 协程
1 引言 并发.并行.串行.同步.异步.阻塞.非阻塞.进程.线程.协程是并发编程中的常见概念,相似却也有却不尽相同,令人头痛,这一篇博文中我们来区分一下这些概念. 2 并发与并行 在解释并发与并行之前 ...
- Python 进程线程协程 GIL 闭包 与高阶函数(五)
Python 进程线程协程 GIL 闭包 与高阶函数(五) 1 GIL线程全局锁 线程全局锁(Global Interpreter Lock),即Python为了保证线程安全而采取的独立线程运行的 ...
- python自动化开发学习 进程, 线程, 协程
python自动化开发学习 进程, 线程, 协程 前言 在过去单核CPU也可以执行多任务,操作系统轮流让各个任务交替执行,任务1执行0.01秒,切换任务2,任务2执行0.01秒,在切换到任务3,这 ...
- 进程&线程&协程
进程 一.基本概念 进程是系统资源分配的最小单位, 程序隔离的边界系统由一个个进程(程序)组成.一般情况下,包括文本区域(text region).数据区域(data region)和堆栈(stac ...
- 多道技术 进程 线程 协程 GIL锁 同步异步 高并发的解决方案 生产者消费者模型
本文基本内容 多道技术 进程 线程 协程 并发 多线程 多进程 线程池 进程池 GIL锁 互斥锁 网络IO 同步 异步等 实现高并发的几种方式 协程:单线程实现并发 一 多道技术 产生背景 所有程序串 ...
- python进程/线程/协程
一 背景知识 顾名思义,进程即正在执行的一个过程.进程是对正在运行程序的一个抽象. 进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一.操作系统的其他所 ...
- python-socket和进程线程协程(代码展示)
socket # 一.socket # TCP服务端 import socket # 导入socket tcp_sk = socket.socket() # 实例化一个服务器对象 tcp_sk.bin ...
随机推荐
- JQ Ajax 上传文件
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 使用BestSync同步软件与坚果云同步
坚果云的免费用户可以享受每个月的1G上传与3G下载流量,同时号称是国内唯一支持WebDAV的云.我的工作备份的文档不多,正好手头有BestSync同步软件可以用.决定试试BestSync的与WebDA ...
- js漂亮的弹出层
1.漂亮的弹出层----artDialog http://aui.github.io/artDialog/ 2.弹出层 ------layer http://sentsin.com/jquery/la ...
- 【PyQt】插入排序算法
# coding=utf-8 import sys from PyQt4.QtGui import * from PyQt4.QtCore import * class MainWindow(QMai ...
- UE寻找Actor
void FTestButtonModule::PluginButtonClicked() { GEngine->AddOnScreenDebugMessage(-, .f, FColor::R ...
- android webview css z-index属性无效
在做android的web页面嵌入的时候,当使用css的z-index设置重叠div失败: 查询google说设置 -webkit-transform:translateZ(0) canvas{ -w ...
- iOS 将金钱变为逗号形式
; NSNumberFormatter * formatter = [NSNumberFormatter new]; [formatter setNumberStyle:NSNumberFormatt ...
- mysql如何判断一个字符串是否包含另外一个字符串?
转自:http://blog.csdn.net/hechurui/article/details/49278493 判断子字符串在父字符串当中的索引: SELECT LOCATE("b&qu ...
- 微信公众号 订单 待发货-配送中-已收货 logic
w function logistics_sameorder($logistics) { $arr = array(); $tmp_wxout_trade_no = ''; $w = 0; $wi = ...
- <2014 05 09> Lucida:我的算法学习之路
[转载] 我的算法学习之路 关于 严格来说,本文题目应该是我的数据结构和算法学习之路,但这个写法实在太绕口——况且CS中的算法往往暗指数据结构和算法(例如算法导论指的实际上是数据结构和算法导论),所以 ...