一、线程

  线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务

方法:

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

  setName      设置线程名称

  getName      获取线程名称

  setDaemon   把一个主进程设置为Daemon线程后,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论有没执行完成,都会停止

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

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

threading模块

  线程的两种调用方式:

1.直接调用(常用)

import threading
import time '''直接调用''' def hello(name):
print("Hello %s"%name)
time.sleep(3) if __name__ == "__main__":
t1=threading.Thread(target=hello,args=("zhangsan",)) #生成线程实例
t2=threading.Thread(target=hello,args=("lisi",)) t1.setName("aaa") #设置线程名
t1.start() #启动线程
t2.start()
t2.join() #join 等待t2先执行完
print("Hello")
print(t1.getName()) #获取线程名

2.继承式调用

'''继承式调用'''
import threading
import time
class MyThread(threading.Thread):
def __init__(self,name):
threading.Thread.__init__(self)
self.name = name
def run(self):
print("Hello %s"%self.name)
time.sleep(3) if __name__ == "__main__":
t1=MyThread("zhangsan")
t2=MyThread("lisi")
t1.start()
t2.start()

setDaemon线程

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import time
import threading
def run(n):
print('Hello..[%s]\n' % n)
time.sleep(2) def main():
for i in range(5):
t = threading.Thread(target=run,args=[i,])
t.start()
t.join(1) m = threading.Thread(target=main,args=[])
m.setDaemon(True) #将主线程设置Daemon设置为True后,主线程执行完成时,其它子线程会同时退出,不管是否执行完任务
m.start()
print("--- done----")

线程锁Lock

  一个进程下可以启动多个线程,多个线程共享父进程的内存空间,每个线程可以访问同一份数据,所以当多个线程同时要修改同一份数据时,就会出现错误

  例如:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import threading
import time num = 100 #设置一个共享变量
def show():
global num #在函数内操作函数外变量,需设置为全局变量
time.sleep(1)
num -= 1
list=[]
for i in range(100):
t = threading.Thread(target=show)
t.start()
list.append(t) for t in list:
t.join()
print(num)

  上面的例子在正常执行完成后的num的结果应该是0,但实际上每次的执行结果都不太一样,因为当多个线程同时要修改同一份数据时,就会出现一些错误(只有

在python2.x运行才会出现错误,python3.x中不会),所以每个线程在要修改公共数据时,为了避免自己在还没改完的时候别人也来修改此数据,可以加上线程锁

来确保每次修改数据时只有一个线程在操作。

  加锁代码

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import threading
import time num = 100 #设置一个共享变量
lock=threading.Lock() #生成全局锁
def show():
global num #在函数内操作函数外变量,需设置为全局变量
time.sleep(1)
lock.acquire() #修改前加锁
num -= 1
lock.release() #修改后解锁
list=[]
for i in range(100):
t = threading.Thread(target=show)
t.start()
list.append(t) for t in list:
t.join() print(num)

递归锁RLock

  就是在一个大锁中再包含子锁

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import threading
#递归锁
def run1():
lock.acquire() #小锁
global num
num +=1
lock.release()
return num
def run2():
lock.acquire() #小锁
global num2
num2+=1
lock.release()
return num2
def run3():
lock.acquire() #大锁
res = run1()
res2 = run2()
lock.release()
print(res,res2) if __name__ == '__main__':
num,num2 = 0,0
lock = threading.RLock() #生成Rlock
for i in range(10):
t = threading.Thread(target=run3)
t.start() while threading.active_count() != 1:#如果不等于1,说明子线程还没执行完毕
pass #打印进程数
else:
print(num,num2)

Semaphore

  同时允许一定数量的线程更改数据

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import threading
import time
def run(n):
semaphore.acquire()
time.sleep(1)
print("run the thread: %s" %n)
semaphore.release() if __name__ == '__main__':
semaphore = threading.BoundedSemaphore(3) #设置最多允许3个线程同时运行
for i in range(20):
t = threading.Thread(target=run,args=(i,))
t.start()
while threading.active_count() != 1:
pass
else:
print('----done---')

event

  实现两个或多个线程间的交互,提供了三个方法 set、wait、clear,默认碰到event.wait 方法时就会阻塞。

  event.set(),设定后遇到wait不阻塞

  event.clear(),设定后遇到wait后阻塞

  event.isSet(),判断有没有被设定

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import threading
def start():
print("---start---1")
event.wait() #阻塞
print("---start---2") if __name__ == "__main__":
event = threading.Event()
t = threading.Thread(target=start)
t.start() result=input(">>:")
if result == "set":
event.set() #设定set,wait不阻塞

二、进程

multiprocessing模块

进程调用

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from multiprocessing import Process
import time
def start(name):
time.sleep(1)
print('hello', name) if __name__ == '__main__':
p = Process(target=start, args=('zhangsan',))
p1 = Process(target=start, args=('lisi',))
p.start()
p1.start()
p.join()

进程间通讯

  每个进程都拥有自己的内存空间,因此不同进程间内存是不共享的,要想实现两个进程间的数据交换,有几种方法

Queue(队列)

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from multiprocessing import Process, Queue
def start(q):
q.put( 'hello') if __name__ == '__main__':
q = Queue()
p = Process(target=start, args=(q,))
p.start()
print(q.get())
p.join()

Pipe(管道,不常用)

  把管道的两头分别赋给两个进程,实现两个进程的互相通信

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from multiprocessing import Process, Pipe def start(conn):
conn.send('hello')#发送
print(conn.recv())#接收
conn.close() if __name__ == '__main__':
parent_conn, child_conn = Pipe() #生成一个管道
p = Process(target=start, args=(child_conn,))
p.start()
print(parent_conn.recv())#接收
parent_conn.send("")#发送
p.join()

Manager(实现了进程间真正的数据共享)

#!/usr/bin/env python
from multiprocessing import Process, Manager
def f(dic, list,i):
dic[''] = 1
dic[''] = 2
dic[''] = 3
list.append(i) if __name__ == '__main__':
manager = Manager()
dic = manager.dict()#通过manager生成一个字典
list = manager.list(range(5))#通过manager生成一个列表
p_list = []
for i in range(10):
p = Process(target=f, args=(dic, list,i))
p.start()
p_list.append(p)
for res in p_list:
res.join() print(dic)
print(list)
#执行结果
'''
{'2': 2, '3': 3, '1': 1}
[0, 1, 2, 3, 4, 1, 9, 2, 5, 3, 7, 6, 0, 8, 4]
'''

进程池

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

进程池中有两个方法:

1、apply(同步)

2、apply_async(异步)

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from multiprocessing import Process,Pool
import time def Foo(i):
time.sleep(1)
return i+100 def Bar(arg):
print('number::',arg) if __name__ == "__main__":
pool = Pool(3)#定义一个进程池,里面有3个进程
for i in range(10):
pool.apply_async(func=Foo, args=(i,),callback=Bar)
#pool.apply(func=Foo, args=(i,)) pool.close()#关闭进程池
pool.join()#进程池中进程执行完毕后再关闭,(必须先close在join)

callback是回调函数,就是在执行完Foo方法后会自动执行Bar函数,并且自动把Foo函数的返回值作为参数传入Bar函数

三、协程

  协程,又称微线程,是一种用户态的轻量级线程。协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置,当程序中存在大量不需要CPU的操作时(IO),适用于协程。

协程有极高的执行效率,因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销。

不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。

因为协程是一个线程执行,所以想要利用多核CPU,最简单的方法是多进程+协程,这样既充分利用多核,又充分发挥协程的高效率。

那符合什么条件就能称之为协程:1、必须在只有一个单线程里实现并发 2、修改共享数据不需加锁 3、用户程序里自己保存多个控制流的上下文栈 4、一个协程遇到IO操作自动切换到其它协程

python中对于协程有两个模块,greenlet和gevent。

Greenlet(greenlet的执行顺序需要我们手动控制)

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from greenlet import greenlet
def test1():
print (11)
gr2.switch() #手动切换
print (22)
gr2.switch() def test2():
print (33)
gr1.switch()
print (44) gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()

gevent(自动切换,由于切换是在IO操作时自动完成,所以gevent需要修改Python自带的一些标准库,这一过程在启动时通过monkey patch完成)

from gevent import monkey; monkey.patch_all()
import gevent
import time def foo():
print('')
time.sleep(3)
print('') def bar():
print('')
print('') gevent.joinall([
gevent.spawn(foo),
gevent.spawn(bar),
])

运行结果:(从结果可以看出,它们是并发执行的)

11
33
44
22

参考:

http://www.cnblogs.com/wupeiqi/articles/5040827.html

http://www.cnblogs.com/alex3714/articles/5230609.html

Python—进程、线程、协程的更多相关文章

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

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

  2. python -- 进程线程协程专题

    进程专栏 multiprocessing 高级模块 要让Python程序实现多进程(multiprocessing),我们先了解操作系统的相关知识. Unix/Linux操作系统提供了一个fork() ...

  3. python 进程 线程 协程

    并发与并行:并行是指两个或者多个事件在同一时刻发生:而并发是指两个或多个事件在同一时间间隔内发生.在单核CPU下的多线程其实都只是并发,不是并行. 进程是系统资源分配的最小单位,进程的出现是为了更好的 ...

  4. python进程/线程/协程

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

  5. python 进程/线程/协程 测试

    # Author: yeshengbao # -- coding: utf-8 -- # @Time : 2018/5/24 21:38 # 进程:如一个人拥有分身(分数数最好为cpu核心数)几乎同时 ...

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

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

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

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

  8. 进程&线程&协程

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

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

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

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

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

随机推荐

  1. 常用JS表单验证方法

    /*输入:str返回:如果全是空返回true,否则返回false*/function isNull(str) {if (str == "") return true;var reg ...

  2. thinkphp 的create()非法数据解决办法

    是因为create()方法默认是使用post传值的,把from表单的传值方法改成post就行了,默认是get.

  3. HTML静态网页 标签、表格

    HTML静态网页: 打开DREAMWEAVER,新建HTML,如下图: body的属性: bgcolor 页面背景色 background  背景壁纸.图片 text  文字颜色 topmargin ...

  4. VB鼠标指针

    vbDefault 0 (缺省值)形状由对象决定. VbArrow 1 箭头. VbCrosshair 2 十字线(crosshair 指针). VbIbeam 3 I 型 VbIconPointer ...

  5. U3D--常用属性(不完整,待加)

    1. AddComponentMenu 描述:这个属性可以在Component这个菜单栏下加自己定义的子菜单,这样可以快速添加常用的脚本.该属性要用在类上. using UnityEngine; us ...

  6. 示例-创建表格&使用表格对象

    @charset "utf-8";/* CSS Document */table{ border:#249bdb 1px solid; width:500px; border-co ...

  7. a标签实用方法详解

    a:link { color: black } /* 未访问时的状态 */ a:visited { color: blue } /* 已访问过的状态 */ a:hover { color: red } ...

  8. php如何遍历多维的stdClass Object 对象,php的转换成数组的函数只能转换外面一丛数组

    php如何遍历多维的stdClass Object 对象,php的转换成数组的函数只能转换外面一丛数组 (2012-09-10 19:58:49) 标签: 杂谈 分类: 网页基础知识 php如何遍历多 ...

  9. Google Chrome浏览器中如何使用命令

    Google Chrome浏览器中如何使用命令 | 浏览:2974 | 更新:2014-02-23 23:12 | 标签:chrome 1 2 3 分步阅读 Google Chrome浏览器有很多的特 ...

  10. ModelAndView学习整理

    ModelAndView mav = new ModelAndView("/media/play-video");是什么意思 1.这是SpringMVC里面的问题啊!2.这叫返回一 ...