博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python基础===进程,线程,协程的区别(转)
阅读量:6787 次
发布时间:2019-06-26

本文共 2297 字,大约阅读时间需要 7 分钟。

本文转自:http://blog.csdn.net/hairetz/article/details/16119911  

  • 进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度。
  • 线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度(标准线程是的)。
  • 协程和线程一样共享堆,不共享栈,协程由程序员在协程的代码里显示调度。

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

打个比方吧,假设有一个操作系统,是单核的,系统上没有其他的程序需要运行,有两个线程 A 和 B ,A 和 B 在单独运行时都需要 10 秒来完成自己的任务,而且任务都是运算操作,A B 之间也没有竞争和共享数据的问题。现在 A B 两个线程并行,操作系统会不停的在 A B 两个线程之间切换,达到一种伪并行的效果,假设切换的频率是每秒一次,切换的成本是 0.1 秒(主要是栈切换),总共需要 20 + 19 * 0.1 = 21.9 秒。如果使用协程的方式,可以先运行协程 A ,A 结束的时候让位给协程 B ,只发生一次切换,总时间是 20 + 1 * 0.1 = 20.1 秒。如果系统是双核的,而且线程是标准线程,那么 A B 两个线程就可以真并行,总时间只需要 10 秒,而协程的方案仍然需要 20.1 秒。

#!/usr/bin/python    # python thread.py    # python -m gevent.monkey thread.py    import threading    class Thread(threading.Thread):        def __init__(self, name):            threading.Thread.__init__(self)            self.name = name        def run(self):            for i in xrange(10):                print self.name    threadA = Thread("A")    threadB = Thread("B")    threadA.start()    threadB.start()

   

python thread.py
A B A B ...
那么总共发生了 20 次切换:主线程 -> A -> B -> A -> B …

#!/usr/bin/python    # python gr.py    import greenlet    def run(name, nextGreenlets):        for i in xrange(10):            print name        if nextGreenlets:            nextGreenlets.pop(0).switch(chr(ord(name) + 1), nextGreenlets)    greenletA = greenlet.greenlet(run)    greenletB = greenlet.greenlet(run)    greenletA.switch('A', [greenletB])

greenlet 是 python 的协程实现。

python gr.py
此时发生了 2 次切换:主协程 -> A -> B
python -m gevent.monkey thread.py
gevent 是基于 greenlet 的一个 python 库,它可以把 python 的内置线程用 greenlet 包装,这样在我们使用线程的时候,实际上使用的是协程,在上一个协程的例子里,协程 A 结束时,由协程 A 让位给协程 B ,而在 gevent 里,所有需要让位的协程都让位给主协程,由主协程决定运行哪一个协程,gevent 也会包装一些可能需要阻塞的方法,比如 sleep ,比如读 socket ,比如等待锁,等等,在这些方法里会自动让位给主协程,而不是由程序员显示让位,这样程序员就可以按照线程的模式进行线性编程,不需要考虑切换的逻辑。
gevent 版的命令发生了 3 次切换:主协程 -> A -> 主协程 -> B
再来说说 python 的线程,python 的线程不是标准线程,在 python 中,一个进程内的多个线程只能使用一个 CPU 。
如果使用 gevent 包装后的线程,程序员就不必承担调度的责任,而 python 的线程本身就没有使用多 CPU 的能力,那么,用 gevent 包装后的线程,取代 python 的内置线程,不是只有避免无意义的调度,提高性能的好处,而没有什么坏处了吗?
答案是否定的。举一个例子,有一个 GUI 程序,上面有两个按钮,一个 运算 一个 取消 ,点击运算,会有一个运算线程启动,不停的运算,点击取消,会取消这个线程,如果使用 python 的内置线程或者标准线程,都是没有问题的,即便运算线程不停的运算,调度器仍然会给 GUI 线程分配时间片,用户可以点击取消,然而,如果使用 gevent 包装后的线程就完蛋了,一旦运算开始,GUI 就会失去相应,因为那个运算线程(协程)霸着 CPU 不让位。不单是 GUI ,所有和用户交互的程序都会有这个问题。

 

转载于:https://www.cnblogs.com/botoo/p/8308411.html

你可能感兴趣的文章
有关tomcat的性能调优【待完善】
查看>>
QA和软件测试员的区别
查看>>
windows 批处理常用指令 -- 持续更新
查看>>
Jenkins+Shell+Docker实现自动化CI/CD发布Java项目
查看>>
【转】Java经典问题:传值与传引用?
查看>>
xp扩容C盘后盘符丢失的资料怎么找到
查看>>
CVE-2017-12617
查看>>
SSH管理服务
查看>>
废旧行业迎来春天 环保部重启绿色GDP研究
查看>>
监控——JVM监控安装
查看>>
Working with System Properties
查看>>
为什么我墙裂建议大家使用枚举来实现单例
查看>>
记一次阿里云服务器安装Python的血泪史
查看>>
c++函数模块与其相关内容
查看>>
ssh防止暴力破解之fail2ban
查看>>
LNMP基础安装配置
查看>>
借助Gradle Plugin解决模块化开发中模块如何对外暴露接口
查看>>
深圳车牌识别助力汽车检测,颠覆传统方式
查看>>
tomcat,tomcat7配置https
查看>>
Linux进程管理
查看>>