简述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之有容乃大的list(3)
Sep 15 Python
Python聚类算法之基本K均值实例详解
Nov 20 Python
Python查找两个有序列表中位数的方法【基于归并算法】
Apr 20 Python
从django的中间件直接返回请求的方法
May 30 Python
Python中关键字global和nonlocal的区别详解
Sep 03 Python
python3+PyQt5 创建多线程网络应用-TCP客户端和TCP服务器实例
Jun 17 Python
SELENIUM自动化模拟键盘快捷键操作实现解析
Oct 28 Python
Windows下Pycharm远程连接虚拟机中Centos下的Python环境(图文教程详解)
Mar 19 Python
如何实现更换Jupyter Notebook内核Python版本
May 18 Python
Python csv文件记录流程代码解析
Jul 16 Python
用python进行视频剪辑
Nov 02 Python
python 如何对logging日志封装
Dec 02 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
Zend公司全球首推PHP认证
2006/10/09 PHP
新浪新闻小偷
2006/10/09 PHP
php 获取select下拉列表框的值
2010/05/08 PHP
浅析application/x-www-form-urlencoded和multipart/form-data的区别
2014/06/22 PHP
Windows下Apache + PHP SESSION丢失的解决过程全纪录
2015/04/07 PHP
thinkPHP模型初始化实例分析
2015/12/03 PHP
PHP面向对象程序设计子类扩展父类(子类重新载入父类)操作详解
2019/06/14 PHP
如何在centos8自定义目录安装php7.3
2019/11/28 PHP
JAVASCRIPT下判断IE与FF的比较简单的方式
2008/10/17 Javascript
40个有创意的jQuery图片和内容滑动及弹出插件收藏集之三
2012/01/03 Javascript
jquery清空textarea等输入框实现代码
2013/04/22 Javascript
jQuery动态设置form表单的enctype值(实现代码)
2013/07/04 Javascript
javascript 弹出的窗口返回值给父窗口具体实现
2013/11/23 Javascript
jQuery动态修改超链接地址的方法
2015/02/13 Javascript
jQuery插件JWPlayer视频播放器用法实例分析
2017/01/11 Javascript
基于JavaScript实现数码时钟效果
2020/03/30 Javascript
jQuery实现的事件绑定功能基本示例
2017/10/11 jQuery
小程序组件之自定义顶部导航实例
2019/06/12 Javascript
Node.js利用Express实现用户注册登陆功能(推荐)
2020/10/26 Javascript
Vue实现图书管理案例
2021/01/20 Vue.js
[37:45]2014 DOTA2国际邀请赛中国区预选赛5.21 DT VS Orenda
2014/05/22 DOTA
python使用reportlab画图示例(含中文汉字)
2013/12/03 Python
Python实现发送QQ邮件的封装
2017/07/14 Python
详解pyppeteer(python版puppeteer)基本使用
2019/06/12 Python
Python+OpenCV+pyQt5录制双目摄像头视频的实例
2019/06/28 Python
Python 生成VOC格式的标签实例
2020/03/10 Python
HTML5 canvas基本绘图之文字渲染
2016/06/27 HTML / CSS
高中体育教学反思
2014/01/24 职场文书
学生宿舍管理制度
2014/01/30 职场文书
运动会解说词200字
2014/02/06 职场文书
三项教育活动实施方案
2014/03/30 职场文书
关于安全的标语
2014/06/10 职场文书
2014群众路线学习笔记
2014/11/06 职场文书
2016全国“质量月”活动标语口号
2015/12/26 职场文书
2019大学生预备党员转正思想汇报
2019/06/21 职场文书
详解Python牛顿插值法
2021/05/11 Python