一、线程

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

方法:

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

  setName      设置线程名称

  getName      获取线程名称

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

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

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

threading模块

  线程的两种调用方式:

1.直接调用(常用)

2.继承式调用

'''继承式调用'''
import threading
import time
class MyThread(threading.Thread):def __init__(self,name):threading.Thread.__init__(self)self.name = namedef 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 timenum = 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 timenum = 100 #设置一个共享变量
lock=threading.Lock()  #生成全局锁
def show():global num  #在函数内操作函数外变量,需设置为全局变量time.sleep(1)lock.acquire()  #修改前加锁num -= 1lock.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 numnum +=1lock.release()return num
def run2():lock.acquire()  #小锁global  num2num2+=1lock.release()return num2
def run3():lock.acquire()  #大锁res = run1()res2 = run2()lock.release()print(res,res2)if __name__ == '__main__':num,num2 = 0,0lock = threading.RLock()    #生成Rlockfor 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, Pipedef 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("11111")#发送p.join()

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

#!/usr/bin/env python
from multiprocessing import Process, Manager
def f(dic, list,i):dic['1'] = 1dic['2'] = 2dic['3'] = 3list.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 timedef Foo(i):time.sleep(1)return i+100def 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 timedef foo():print('11')time.sleep(3)print('22')def bar():print('33')print('44')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进程线程协程区别_Python3多线程与协程

    python中的多线程非常的常用,之前一直糊里糊涂地使用,没有一些系统性的概念,记录一下~ 0x001 多线程的优势:可将长时间占用的程序放到后台 可能会加速程序执行速度 能够实现一些类似同步执行的效 ...

  2. python 进程 线程 协程

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

  3. python进程线程协程区别_进程和线程、协程的区别

    现在多进程多线程已经是老生常谈了,协程也在最近几年流行起来.python中有协程库gevent,py web框架tornado中也用了gevent封装好的协程.本文主要介绍进程.线程和协程三者之间的区 ...

  4. python进程线程协程区别_Python中 进程 线程 协程

    一.进程 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础.在早期面向进程设计的计算机结构中,进程是程序的基本执行实体:在 ...

  5. Python之进程+线程+协程(异步、selectors模块、阻塞、非阻塞IO)

    文章目录 一.IO多路复用 二.selectors模块 本篇文字是关于IO多路复用的更深入一步的总结,上一篇 Python之进程+线程+协程(事件驱动模型.IO多路复用.select与epoll)对I ...

  6. linux的进程/线程/协程系列5:协程的发展复兴与实现现状

    协程的发展复兴与实现现状 前言 本篇摘要: 1. 协同制的发展史 1.1 协同工作制的提出 1.2 自顶向下,无需协同 1.3 协同式思想的应用 2. 协程的复兴 2.1 高并发带来的问题 2.2 制 ...

  7. 简要说明__python3中的进程/线程/协程

    多任务可以充分利用系统资源,极大提升程序运行效率,多任务的实现往往与 多线程,多进程,多协程有关 稳定性: 进程 > 线程 > 协程 系统资源占用量:进程 > 线程 > 协程 ...

  8. Linux的进程/线程/协程系列4:进程知识深入总结:上篇

    Linux的进程/线程/协程系列4:进程/线程相关知识总结 前言 本篇摘要: 1. 进程基础知识 1.1 串行/并行与并发 1.2 临界资源与共享资源 1.3 同步/异步与互斥 1.4 进程控制原语 ...

  9. linux的进程/线程/协程系列3:查看linux内核源码——vim+ctags/find+grep

    linux的进程/线程/协程系列3:查看linux内核源码--vim+ctags/find+grep 前言 摘要: 1. 下载linux内核源码 2. 打标签方法:vim+ctags 2.1 安装vi ...

  10. linux的进程/线程/协程系列1:进程到协程的演化

    linux的进程/线程/协程系列1:进程到协程的演化 前言 摘要: 1. 一些历史:批处理时代 2. 现代操作系统启动过程 3. 进程(process)的出现 4. 线程(thread)与线程池 5. ...

最新文章

  1. macos怎么pdf转换成word,妈妈再也不用担心我的mac了
  2. 运动会成绩管理java代码_基于jsp的运动会成绩管理-JavaEE实现运动会成绩管理 - java项目源码...
  3. linux挂载硬盘读写,mount 挂载第二块硬盘,普通用户可以读写
  4. mysql 创建事件_mysql怎么建立事件
  5. 机械制图符号_《机械制图》试卷
  6. 初识C++之函数重载、重写、重定义的区别
  7. OCP-052考试题库汇总(60)-CUUG内部解答版
  8. thinkphp超简图床源码V1.0
  9. TensorFlow神经网络(八)卷积神经网络之Lenet-5
  10. 【经典】Noip动态规划
  11. BDD(行为驱动开发)
  12. python打开快捷方式_Python打开一个JAR快捷方式
  13. mysql with 查询_mysql笔记(6)-多表查询之with
  14. 最新如何解决git 输入github时每次都要输入用户名和密码问题
  15. 用wim还原服务器系统,如何使用黑鲨PE中的Dism++工具对WIM文件进行系统还原
  16. 解决post请求跨域请求第三方服务器
  17. ROS 端口IP映射 动态IP映射
  18. 日期计算(来自计蒜客)
  19. 看看别人家的神仙公司
  20. 简易网页版进程管理器(支持手机管理电脑进程)

热门文章

  1. VMware下主机与虚拟机通信问题
  2. 牛客多校3 - Fraction Construction Problem(扩展欧几里得)
  3. CodeForces - 1373D Maximum Sum on Even Positions(最大连续子段和)
  4. HDU - 4513 吉哥系列故事——完美队形II(Manacher)
  5. vb编程软件_原创经验,如何安装vb编程软件
  6. Collecting package metadata (current_repodata.json): done Solving environment: failed with repodata
  7. 远程登录另一个mysql 数据库_Ubuntu中开启MySQL远程访问功能,并将另一个数据库服务器中的数据迁移到新的服务器中...
  8. 通讯故障_伦茨lenze全数字直流调速器通讯故障维修经验很丰富
  9. L1-036. A乘以B
  10. C++中placement new操作符(经典)