简述Python中的进程、线程、协程


Posted in Python onMarch 18, 2016

进程、线程和协程之间的关系和区别也困扰我一阵子了,最近有一些心得,写一下。

进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度。

线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度(标准线程是的)。

协程和线程一样共享堆,不共享栈,协程由程序员在协程的代码里显示调度。

进程和其他两个的区别还是很明显的。

协程和线程的区别是:协程避免了无意义的调度,由此可以提高性能,但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力。

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):
t = threading.Thread(target=show, args=(i,))
t.start()
print 'main thread stop

上述代码创建了10个“前台”线程,然后控制器就交给了CPU,CPU根据指定算法进行调度,分片执行指令。

更多方法:

•start 线程准备就绪,等待CPU调度

•setName 为线程设置名称

•getName 获取线程名称

•setDaemon 设置为后台线程或前台线程(默认)

如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均停止

如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止

•join 逐个执行每个线程,执行完毕后继续往下执行,该方法使得多线程变得无意义

•run 线程被cpu调度后自动执行线程对象的run方法

线程锁

由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,CPU接着执行其他线程。所以,可能出现如下问题:

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' 

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()

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()
print 'execute'
event_obj = threading.Event()
for i in range(10):
t = threading.Thread(target=do, args=(event_obj,))
t.start()
event_obj.clear()
inp = raw_input('input:')
if inp == 'true':
event_obj.set()

Python 进程

from multiprocessing import Process
import threading
import time
def foo(i):
print 'say hi',i
for i in range(10):
p = Process(target=foo,args=(i,))
p.start()

注意:由于进程之间的数据需要各自持有一份,所以创建进程需要的非常大的开销。

进程数据共享

进程各自持有一份数据,默认无法共享数据

#!/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)

#方法一,Array

from multiprocessing import Process,Array
temp = Array('i', [11,22,33,44])
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,Manager
manage = Manager()
dic = manage.dict()
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() 
'c': ctypes.c_char, 'u': ctypes.c_wchar,
'b': ctypes.c_byte, 'B': ctypes.c_ubyte,
'h': ctypes.c_short, 'H': ctypes.c_ushort,
'i': ctypes.c_int, 'I': ctypes.c_uint,
'l': ctypes.c_long, 'L': ctypes.c_ulong,
'f': ctypes.c_float, 'd': ctypes.c_double

当创建进程时(非使用时),共享数据会被拿到子进程中,当进程中执行完毕后,再赋值给原值。

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from multiprocessing import Process, Array, RLock
def Foo(lock,temp,i):
"""
将第0个数加100
"""
lock.acquire()
temp[0] = 100+i
for item in temp:
print i,'----->',item
lock.release()
lock = RLock()
temp = Array('i', [11, 22, 33, 44])
for i in range(20):
p = Process(target=Foo,args=(lock,temp,i,))
p.start()

进程池

进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。

进程池中有两个方法:

•apply

•apply_async

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from multiprocessing import Process,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,))
#print pool.apply_async(func =Foo, args=(1,)).get()
for i in range(10):
pool.apply_async(func=Foo, args=(i,),callback=Bar)
print 'end'
pool.close()

pool.join()#进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭

协程

线程和进程的操作是由程序触发系统接口,最后的执行者是系统;协程的操作则是程序员。

协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时(保存状态,下次继续)。协程,则只使用一个线程,在一个线程中规定某个代码块执行顺序。

协程的适用场景:当程序中存在大量不需要CPU的操作时(IO),适用于协程;

greenlet

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from greenlet import greenlet
def test1():
print 12
gr2.switch()
print 34
gr2.switch()
def test2():
print 56
gr1.switch()
print 78
gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()

gevent

import gevent
def foo():
print('Running in foo')
gevent.sleep(0)
print('Explicit context switch to foo again')
def bar():
print('Explicit context to bar')
gevent.sleep(0)
print('Implicit context switch back to bar')
gevent.joinall([
gevent.spawn(foo),
gevent.spawn(bar),
])

遇到IO操作自动切换:

from gevent import monkey; monkey.patch_all()
import gevent
import urllib2
def f(url):
print('GET: %s' % url)
resp = urllib2.urlopen(url)
data = resp.read()
print('%d bytes received from %s.' % (len(data), url))
gevent.joinall([
gevent.spawn(f, 'https://www.python.org/'),
gevent.spawn(f, 'https://www.yahoo.com/'),
gevent.spawn(f, 'https://github.com/'),
])

以上所述是小编给大家介绍的Python中的进程、线程、协程的相关知识,希望对大家有所帮助!

Python 相关文章推荐
Python编写屏幕截图程序方法
Feb 18 Python
Python实现文件复制删除
Apr 19 Python
TensorFlow模型保存/载入的两种方法
Mar 08 Python
python实现批量按比例缩放图片效果
Mar 30 Python
详解pyqt5 动画在QThread线程中无法运行问题
May 05 Python
python 遍历目录(包括子目录)下所有文件的实例
Jul 11 Python
Python 实现王者荣耀中的敏感词过滤示例
Jan 21 Python
python 统计文件中的字符串数目示例
Dec 24 Python
python和js交互调用的方法
Jun 23 Python
python3.x中安装web.py步骤方法
Jun 23 Python
python中upper是做什么用的
Jul 20 Python
pytorch加载语音类自定义数据集的方法教程
Nov 10 Python
Python实现计算最小编辑距离
Mar 17 #Python
Python引用模块和查找模块路径
Mar 17 #Python
Python使用tablib生成excel文件的简单实现方法
Mar 16 #Python
Python保存MongoDB上的文件到本地的方法
Mar 16 #Python
Python3中的真除和Floor除法用法分析
Mar 16 #Python
学习python类方法与对象方法
Mar 15 #Python
Python 的内置字符串方法小结
Mar 15 #Python
You might like
在PHP中使用curl_init函数的说明
2010/11/02 PHP
php5.3 goto函数介绍和示例
2014/03/21 PHP
Linux中用PHP判断程序运行状态的2个方法
2014/05/04 PHP
thinkphp 手机号和用户名同时登录
2017/01/20 PHP
PHP设计模式之观察者模式定义与用法分析
2019/04/04 PHP
Laravel 实现Eloquent模型分组查询并返回每个分组的数量 groupBy()
2019/10/23 PHP
jQuery编辑器KindEditor4.1.4代码高亮显示设置教程
2013/03/01 Javascript
jQuery页面图片伴随滚动条逐渐显示的小例子
2013/03/21 Javascript
js中parseInt函数浅谈
2013/07/31 Javascript
解析img图片没找到onerror事件 Stack overflow at line: 0
2013/12/23 Javascript
JS实现同时搜索百度和必应的方法
2015/01/27 Javascript
提升jQuery的性能需要做好七件事
2016/01/11 Javascript
nodejs 中模拟实现 emmiter 自定义事件
2016/02/22 NodeJs
JavaScript中的闭包
2016/02/24 Javascript
js多功能分页组件layPage使用方法详解
2016/05/19 Javascript
浅谈EasyUI常用控件的禁用方法
2016/11/09 Javascript
js控制一个按钮是否可点击(可使用)disabled的实例
2017/02/14 Javascript
Node.js使用Express.Router的方法
2017/11/14 Javascript
Angular4自制一个市县二级联动组件示例
2017/11/21 Javascript
JS实现select选中option触发事件操作示例
2018/07/13 Javascript
koa源码中promise的解读
2018/11/13 Javascript
小程序实现录音上传功能
2019/11/22 Javascript
详解Vue中的自定义指令
2020/12/07 Vue.js
el-table表头根据内容自适应完美解决表头错位和固定列错位
2021/01/07 Javascript
python对url格式解析的方法
2015/05/13 Python
Python文件及目录操作实例详解
2015/06/04 Python
Python的Django框架中if标签的相关使用
2015/07/15 Python
python验证码识别的实例详解
2016/09/09 Python
pandas read_excel()和to_excel()函数解析
2019/09/19 Python
利用python查看数组中的所有元素是否相同
2021/01/08 Python
python常量折叠基础知识点讲解
2021/02/28 Python
澳大利亚购买健身器材网站:Gym Direct
2019/12/19 全球购物
计算机应用专业毕业生求职信
2013/10/24 职场文书
综合办公室主任职责
2013/12/16 职场文书
2016年七夕爱情寄语
2015/12/04 职场文书
Spring Cache和EhCache实现缓存管理方式
2021/06/15 Java/Android