简述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 相关文章推荐
9种python web 程序的部署方式小结
Jun 30 Python
Python while、for、生成器、列表推导等语句的执行效率测试
Jun 03 Python
Python使用openpyxl读写excel文件的方法
Jun 30 Python
Python 多核并行计算的示例代码
Nov 07 Python
python如何实现int函数的方法示例
Feb 19 Python
详解python多线程、锁、event事件机制的简单使用
Apr 27 Python
Python基础教程之异常详解
Jan 10 Python
python实现坦克大战游戏 附详细注释
Mar 27 Python
django框架防止XSS注入的方法分析
Jun 21 Python
用django设置session过期时间的方法解析
Aug 05 Python
Python3实现mysql连接和数据框的形成(实例代码)
Jan 17 Python
基于Python3.6中的OpenCV实现图片色彩空间的转换
Feb 03 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
帝国cms常用标签汇总
2015/07/06 PHP
PHP基于新浪IP库获取IP详细地址的方法
2017/05/04 PHP
PHP的PDO大对象(LOBs)
2019/01/27 PHP
js arguments.callee的应用代码
2009/05/07 Javascript
javascript 强制刷新页面的实现代码
2009/12/13 Javascript
jQuery 获取对象 定位子对象
2010/05/31 Javascript
基于jquery的不规则矩形的排列实现代码
2012/04/16 Javascript
js页面跳转的常用方法整理
2013/10/18 Javascript
javascript实现回车键提交表单方法总结
2015/01/10 Javascript
JS+CSS实现可拖动的弹出提示框
2015/02/16 Javascript
JS数组array元素的添加和删除方法代码实例
2015/06/01 Javascript
9个让JavaScript调试更简单的Console命令
2016/11/14 Javascript
React Native中Navigator的使用方法示例
2017/10/13 Javascript
使用proxy实现一个更优雅的vue【推荐】
2018/06/19 Javascript
Angular5.0 子组件通过service传递值给父组件的方法
2018/07/13 Javascript
Vuejs开发环境搭建及热更新【推荐】
2018/09/07 Javascript
解决Layui中layer报错的问题
2019/09/03 Javascript
Openlayers3实现车辆轨迹回放功能
2020/09/29 Javascript
Python 的 Socket 编程
2015/03/24 Python
python 实现tar文件压缩解压的实例详解
2017/08/20 Python
Python中表示字符串的三种方法
2017/09/06 Python
Python基于identicon库创建类似Github上用的头像功能
2017/09/25 Python
1分钟快速生成用于网页内容提取的xslt
2018/02/23 Python
在python中安装basemap的教程
2018/09/20 Python
python 实现保存最新的三份文件,其余的都删掉
2019/12/22 Python
python代码xml转txt实例
2020/03/10 Python
pyinstaller打包找不到文件的问题解决
2020/04/15 Python
英国最大线上综合鞋类商城:Office
2017/12/08 全球购物
英国家居用品和床上用品零售商:P&B Home
2020/01/16 全球购物
十佳大学生村官事迹
2014/01/09 职场文书
小学信息技术教学反思
2014/02/10 职场文书
药品促销活动方案
2014/02/14 职场文书
化工专业自荐书
2014/06/16 职场文书
十二生肖观后感
2015/06/12 职场文书
PHP设计模式(观察者模式)
2021/07/07 PHP
Nginx进程调度问题详解
2021/09/25 Servers