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进阶——进程/线程/协程的更多相关文章

  1. python的进程/线程/协程

    1.python的多线程 多线程就是在同一时刻执行多个不同的程序,然而python中的多线程并不能真正的实现并行,这是由于cpython解释器中的GIL(全局解释器锁)捣的鬼,这把锁保证了同一时刻只有 ...

  2. Python中进程线程协程小结

    进程与线程的概念 进程 程序仅仅只是一堆代码而已,而进程指的是程序的运行过程.需要强调的是:同一个程序执行两次,那也是两个进程. 进程:资源管理单位(容器). 线程:最小执行单位,管理线程的是进程. ...

  3. Python并发编程系列之常用概念剖析:并行 串行 并发 同步 异步 阻塞 非阻塞 进程 线程 协程

    1 引言 并发.并行.串行.同步.异步.阻塞.非阻塞.进程.线程.协程是并发编程中的常见概念,相似却也有却不尽相同,令人头痛,这一篇博文中我们来区分一下这些概念. 2 并发与并行 在解释并发与并行之前 ...

  4. Python 进程线程协程 GIL 闭包 与高阶函数(五)

    Python 进程线程协程 GIL 闭包 与高阶函数(五) 1 GIL线程全局锁 ​ 线程全局锁(Global Interpreter Lock),即Python为了保证线程安全而采取的独立线程运行的 ...

  5. python自动化开发学习 进程, 线程, 协程

    python自动化开发学习 进程, 线程, 协程   前言 在过去单核CPU也可以执行多任务,操作系统轮流让各个任务交替执行,任务1执行0.01秒,切换任务2,任务2执行0.01秒,在切换到任务3,这 ...

  6. 进程&线程&协程

    进程  一.基本概念 进程是系统资源分配的最小单位, 程序隔离的边界系统由一个个进程(程序)组成.一般情况下,包括文本区域(text region).数据区域(data region)和堆栈(stac ...

  7. 多道技术 进程 线程 协程 GIL锁 同步异步 高并发的解决方案 生产者消费者模型

    本文基本内容 多道技术 进程 线程 协程 并发 多线程 多进程 线程池 进程池 GIL锁 互斥锁 网络IO 同步 异步等 实现高并发的几种方式 协程:单线程实现并发 一 多道技术 产生背景 所有程序串 ...

  8. python进程/线程/协程

    一 背景知识 顾名思义,进程即正在执行的一个过程.进程是对正在运行程序的一个抽象. 进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一.操作系统的其他所 ...

  9. python-socket和进程线程协程(代码展示)

    socket # 一.socket # TCP服务端 import socket # 导入socket tcp_sk = socket.socket() # 实例化一个服务器对象 tcp_sk.bin ...

随机推荐

  1. php 判断时间是否超过

    $str="2014-10-11"; echo "".strtotime($str); echo "<br/>"; echo & ...

  2. CSS之webkit-scrollbar例子

    基于webkit的浏览器现在也可以自定义其样式: ::-webkit-scrollbar              { /* 1 */ }   ::-webkit-scrollbar-button   ...

  3. HTML表单页面的运用

    本章目标:掌握表单基本结构<form> 掌握各种表单元素 能理解post和get两种提交方式的区别 本章重点:掌握各种表单元素 本章难点:post和get两种提交方式的区别 一.    H ...

  4. ASP.NET实现推送文件到浏览器的方法

    这篇文章主要介绍了ASP.NET实现推送文件到浏览器的方法,可实现将文件推送到浏览器供用户浏览或下载的功能,需要的朋友可以参考下 本文实例讲述了ASP.NET实现推送文件到浏览器的方法.分享给大家供大 ...

  5. ORB特征提取与匹配

    ORB特征是目前最优秀的特征提取与匹配算法之一,下面具体讲解一下: 特征点的检测 图像的特征点可以简单的理解为图像中比较显著显著的点,如轮廓点,较暗区域中的亮点,较亮区域中的暗点等.ORB采用FAST ...

  6. Cocos2d-x 3.3Bate0 ExpandedListView

    之前写的ExpandedListView版本号因为版本号升级这里提供Cocos2d-x 3.3Bate0 版本号 代码下载:http://download.csdn.net/detail/qqmcy/ ...

  7. IOS开发之自定义键盘

     本文转载至 http://blog.csdn.net/majiakun1/article/details/41242069 实际开发过程中,会有自定义键盘的需求,比如,需要添加一个表情键盘.本文提供 ...

  8. Android开发:《Gradle Recipes for Android》阅读笔记(翻译)5.4——使用Espresso测试Activity

    问题: 你想要使用Google的Espresso测试Activity. 解决方案: 在Gradle配置里面增加Espresso,书写测试脚本. 讨论: Espresso测试库已经被添加进“Androi ...

  9. Android 中替代 sharedpreferences 工具类的实现

    Android 中替代 sharedpreferences 工具类的实现 背景 想必大家一定用过 sharedpreferences 吧!就我个人而言,特别讨厌每次 put 完数据还要 commit. ...

  10. Delphi数据库处理

    Delphi数据库处理 第一节 BDE.ADO.InterBase和dbExpress Delphi中处理数据库主要有两种方法,也就是BDE.ADO,从Delphi 6.0开始还加入了一种dbExpr ...