Python并发式编程
进程
进程就是一个程序在一个数据集上的一次动态执行过程,一般由程序、数据集和进程控制块三部分组成;
程序用来描述进程要完成哪些功能以及如何完成;
数据集则是程序在执行过程中所需要使用的资源;
进程控制块用来记录进程的外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程,它是系
统感知进程存在的唯一标志.
在一个程序的运行过程中,因为一个CPU在一个时间点只能运行一个程序,不过为了保持并发的效果,程序必须不断地切换,使得每一个程序在一定时间内都能被执行一次.这样进程就出现了.
线程
一个整体的程序运行可能要被分成许多不同的进程,但是进程之间却无法进行通信,因此为了降低上下文切换的消耗,提高系统的并发性,并突破一个进程只能干一件事的缺陷,线程就诞生了.
线程也叫轻量级进程,它是一个基本的CPU执行单元,也是程序执行过程中的最小单元,它没有自己独立的内存单位,而是和多个线程共享一个内存单位.其本质是由线程ID、程序计数器、寄存器集合和堆栈共同组成.线程的引入减小了程序并发执行时的开销,提高了操作系统的并发性能.线程没有自己的系统资源.
进程是最小的资源单位,线程是最小的执行单位
GIL(Global Interpreter Lock)
在Python里面,不管有多少CPU和过程,Python都只会默认的让一个CPU按顺序地一个一个地执行进程.
线程的调用方式
直接调用
import threading, time ##调用threading模块
def test(num): ##创建一个函数
print("It's %s" %num)
time.sleep(3)
print("%s end" %num)
if __name__ == "__main__":
t1 = threading.Thread(target = test, args = (1,)) ##调用Thread方法,并传入函数和值
t2 = threading.Thread(target = test, args = (2,))
t1.start() ##让线程开始运作
t2.start()
print("End")
It's 1
It's 2
End
1 end
2 end
继承调用
import threading, time
class MyTread(threading.Thread):
def __init__(self, num):
threading.Thread.__init__(self)
self.num = num
def run(self):
print("我打印的数值是%s" %self.num)
time.sleep(3)
print("%s打印完了" %self.getName())
if __name__ == "__main__":
s1 = MyTread(1)
s2 = MyTread(2)
s1.start()
s2.start()
print("End……")
我打印的数值是1
我打印的数值是2
End……
##(等了3秒)
Thread-1打印完了
Thread-2打印完了
join&Daemon方法
在子线程完成运行之前,这个子线程的父进程将一直被阻塞
import threading, time
class ListenMusic(threading.Thread):
def __init__(self, name):
threading.Thread.__init__(self)
self.name = name
def run(self):
print("%s is listening music! %s" %(self.name,time.ctime()))
time.sleep(4)
print("OK! %s" %time.ctime())
class DoHomework(threading.Thread):
def __init__(self, name):
threading.Thread.__init__(self)
self.name = name
def run(self):
print("%s is doing homework! %s" %(self.name, time.ctime()))
time.sleep(2)
print("Homework has been done! %s" %time.ctime())
if __name__ == "__main__":
s1 = ListenMusic("Hermaeus")
s2 = DoHomework("YuanMing")
s1.start()
s2.start()
# s1.join()
s2.join()
print("End…… %s" %time.ctime())
Hermaeus is listening music! Wed Aug 29 17:49:54 2018
YuanMing is doing homework! Wed Aug 29 17:49:54 2018
Homework has been done! Wed Aug 29 17:49:56 2018
End…… Wed Aug 29 17:49:56 2018
OK! Wed Aug 29 17:49:58 2018
Daemon(True)
将线程申明为守护线程,只要主线程执行完退出那么守护线程也会退出.
import threading, time
class ListenMusic(threading.Thread):
def __init__(self, name):
threading.Thread.__init__(self)
self.name = name
def run(self):
print("%s is listening music! %s" %(self.name,time.ctime()))
time.sleep(4)
print("OK! %s" %time.ctime())
class DoHomework(threading.Thread):
def __init__(self, name):
threading.Thread.__init__(self)
self.name = name
def run(self):
print("%s is doing homework! %s" %(self.name, time.ctime()))
time.sleep(2)
print("Homework has been done! %s" %time.ctime())
if __name__ == "__main__":
s1 = ListenMusic("Hermaeus")
s2 = DoHomework("YuanMing")
s1.setDaemon(True) ##这个必须放在start()方法前面
s1.start()
s2.start()
print("End…… %s" %time.ctime())
Hermaeus is listening music! Wed Aug 29 18:32:52 2018
YuanMing is doing homework! Wed Aug 29 18:32:52 2018
End…… Wed Aug 29 18:32:52 2018
Homework has been done! Wed Aug 29 18:32:54 2018
同步锁
执行下面代码,会每得到不同的值,那是因为在执行IO操作时,有的线程没有了原来的数据,又有的线程拿到了被执行过后的数据,导致数据之间混乱.
import time
import threading
def addNum():
global num
temp=num
time.sleep(0.0012)
num =temp-1
num = 100
for i in range(100):
t = threading.Thread(target=addNum)
t.start()
print('final num:', num )
我们可以使用同步锁来使得数据之间能同步,
import time, threading
def test():
global num
lock.acquire() ##用acquire和release锁住
temp = num
time.sleep(0.00001)
num = temp - 1
lock.release()
num = 100
lock = threading.Lock() ##实例化一个同步锁
l = []
for i in range(100):
s = threading.Thread(target = test)
s.start()
l.append(s)
for ready in l:
ready.join() ##必须要join每一个线程
print(num)
死锁
在多个线程里面,几个线程占有一定资源,并且等待对方释放资源以使用,这样就会导致死锁现象
import threading,time class myThread(threading.Thread):
def doA(self):
lockA.acquire()
print(self.name,"gotlockA",time.ctime())
time.sleep(3)
lockB.acquire()
print(self.name,"gotlockB",time.ctime())
lockB.release()
lockA.release() def doB(self):
lockB.acquire()
print(self.name,"gotlockB",time.ctime())
time.sleep(2)
lockA.acquire()
print(self.name,"gotlockA",time.ctime())
lockA.release()
lockB.release() def run(self):
self.doA()
self.doB()
if __name__=="__main__": lockA=threading.Lock()
lockB=threading.Lock()
threads=[]
for i in range(5):
threads.append(myThread())
for t in threads:
t.start()
for t in threads:
t.join() Thread-1 gotlockA Wed Aug 29 19:16:53 2018
Thread-1 gotlockB Wed Aug 29 19:16:56 2018
Thread-1 gotlockB Wed Aug 29 19:16:56 2018
Thread-2 gotlockA Wed Aug 29 19:16:56 2018
………………………………(会僵死在这里)
递归锁
为了支持在同一线程中多次请求同一资源,python提供了“可重入锁”:threading.RLock。RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次acquire。直到一个线程所有的acquire都被release,其他的线程才能获得资源。
import threading,time
class myThread(threading.Thread):
def doA(self):
lock.acquire()
print(self.name,"gotlockA",time.ctime())
time.sleep(3)
lock.acquire()
print(self.name,"gotlockB",time.ctime())
lock.release()
lock.release()
def doB(self):
lock.acquire()
print(self.name,"gotlockB",time.ctime())
time.sleep(2)
lock.acquire()
print(self.name,"gotlockA",time.ctime())
lock.release()
lock.release()
def run(self):
self.doA()
self.doB()
if __name__=="__main__":
lock = threading.RLock() ##创建一个递归锁的实例
threads = []
for i in range(2):
threads.append(myThread())
for t in threads:
t.start()
for t in threads:
t.join()
同步条件
同步条件是一个简单的同步对象,一个同步条件就相当于一个中间标志;线程会等待直到标志被设置和清除。
当标志被设定后,wait方法不会造成任何影响,但是当标志被清除后,wait会阻塞线程
import threading,time
class Boss(threading.Thread):
def run(self):
print("BOSS:今晚大家都要加班到22:00。")
print(event.isSet())
event.set()
time.sleep(3)
print("BOSS:<22:00>可以下班了。")
print(event.isSet())
event.set()
class Worker(threading.Thread):
def run(self):
event.wait()
print("Worker:哎……命苦啊!")
time.sleep(1)
event.clear()
event.wait()
print("Worker:OhYeah!")
if __name__=="__main__":
event=threading.Event()
threads=[]
for i in range(5):
threads.append(Worker())
threads.append(Boss())
for t in threads:
t.start()
for t in threads:
t.join() BOSS:今晚大家都要加班到22:00。
False
Worker:哎……命苦啊!
Worker:哎……命苦啊!
Worker:哎……命苦啊!
Worker:哎……命苦啊!
Worker:哎……命苦啊!
BOSS:<22:00>可以下班了。
False
Worker:OhYeah!
Worker:OhYeah!
Worker:OhYeah!
Worker:OhYeah!
Worker:OhYeah!
信号量(Semaphore)
信号量用来控制线程并发数,BoundedSemaphore和Semaphore管理一个内置的计数器,调用一次acquire方法时-1,
调用一次release方法时+1。如果计数器为0时,将会阻塞,直到其他线程release释放。BoundedSemaphore会在每一次调用release方式检查计数器是否超过了计数器的初始值,如果超过了就会抛出一个异常。
import threading, time
class MyThread(threading.Thread):
def run(self):
if semaphore.acquire(): ## 判断
print("%s start %s" %(self.getName, time.ctime))
time.sleep(2.5)
print("%s end %s" %(self.getName, time.ctime))
semaphore.release()
if __name__ == "__main__":
semaphore = threading.Semaphore(5) ##实例化一个信号量
threads = []
for i in range(20):
threads.append(MyThread())
for i in threads:
i.start()
for i in threads:
i.join()
队列
这是解决多线程的重要利器,可以让每一个线程都能拿到队列里面的数据。
import time, threading, queue, random
q_list = queue.Queue() ##实例化一个队列,里面自定义了一个maxsize为无限大小,可修改
##Queue是先进先出,LifoQueue是先进后出,PriorityQueue是优先级别越低越先出来
def add_num():
for i in range(10):
q_list.put(i) ##put是放入数据
time.sleep(random.randint(1,2))
print("add_num run over!")
def minus_num():
while True:
if not q_list.empty(): ##empty是判断队列是否为空
print("取得数据 %s" %q_list.get())
time.sleep(random.randint(2,4))
else:
print("minus_num run over!")
break
s1 = threading.Thread(target=add_num)
s2 = threading.Thread(target=minus_num)
s1.start()
s2.start()
q_list.qsize() ##返回队列大小
q_list.full() ##判读队列是否是满的
q_list.put() ##lock为可选参数,默认为1,如果队列当前为空且block为1,put()方法就使调用线程暂停,直到空出一个数据单元;如果block为0,put方法将引发Full异常。
q_list.get([block[,timeout]]) ##获取队列。选参数为block,默认为True。如果队列为空且block为True,get()就使调用线程暂停,直至有项目可用;如果队列为空且block为False,队列将引发Empty异常。timeout是等待时间。
q_list.get_nowait() ##相当于q_list(False)
q_list.put_nowait() ##相当于q_list(item, False)
q_list.task_done() ##完成一项工作后,向任务已经完成的队列发送信号
q_list.join() ##等队列为空,才执行别的操作
多进程模块
该模块可以利用multiprocessing.Process对象来创建一个进程,其用法与threading包中的同名类一致,所以multiprocessing的很大一部分与threading使用同一套API,只不过换到了多进程的情景。
#####构造方法
Process([group [, target [, name [, args [, kwargs]]]]])
#group:线程组,因为没有实现所以引用时提示必须是None
#target:要执行的函数
#name:进程名
#args/kwargs:要传入的参数
#####实例的方法
is_alive():#返回进程是否在运行
join([timeout]):#阻塞进程,直达调用此方法的进程终止或到达指定的timeout
start():#调用进程
run():#在继承式调用里面,必须覆盖这个函数
terminate():#不管任务是否完成,立即停止工作
#####属性
daemon:#和线程的setDeamon功能一样 #p.daemon=True
name:#进程名字
pid:#进程号
#####实例化
from multiprocessing import Process
import time
def f(name):
time.sleep(1)
print("Hello %s %s" %(name, time.ctime()))
if __name__ == "__main__":
p_list = []
for i in range(3):
p = Process(target = f, args = ("Hermaeus",))
p_list.append(p)
p.start()
#####继承式
from multiprocessing import Process
import time
class MyProcess(Process):
def __init__(self, name):
super(MyProcess, self).__init__()
self.name = name
def run(self):
time.sleep(1)
print("Hello %s %s" %(self.name, time.ctime()))
if __name__ == "__main__":
p_list = []
for i in range(3):
p = MyProcess("Hermaeus")
p.start()
p_list.append(p)
进程间通讯
Queue
from multiprocessing import Process, Queue
def test(q,i): ##要把队列名字和值一起传进去
q.put(i)
if __name__ == "__main__":
q = Queue()
for i in range(3):
p = Process(target = test, args = (q,i,))
p.start()
print(q.get())
print(q.get())
print(q.get())
Pipe
from multiprocessing import Process, Pipe
def f(conn):
conn.send("OK!")
response = conn.recv()
print("response: %s" %response)
conn.close()
if __name__ == "__main__":
parent_conn, child_conn = Pipe()
p = Process(target = f, args = (child_conn,))
p.start()
print(parent_conn.recv())
parent_conn.send("From parent_conn!")
p.join()
Managers
from multiprocessing import Process, Manager
def test(d,l,n):
d[n] = n
l.append(n)
if __name__ == "__main__":
with Manager() as manager:
d = manager.dict()
l = manager.list()
p_list = []
for i in range(10):
p = Process(target=test, args=(d,l,i,))
p.start()
p_list.append(p)
for p in p_list: ##必须要有join
p.join()
print(d)
print(l)
进程同步
from multiprocessing import Process, Lock
import time
def test(l,i):
l.acquire()
time.sleep(3)
print("Hi, %s" %i)
l.release()
if __name__ == "__main__":
lock = Lock()
for i in range(3):
p = Process(target=test, args=(lock, i))
p.start()
进程池
from multiprocessing import Process, Pool
import time, os
def test(i):
time.sleep(1)
print("From test %s" %os.getpid())
return "Hello, %s" %i
def Fd(arg):
print(arg)
if __name__ == "__main__":
pool = Pool(2) ##实例化池
for i in range(10):
pool.apply(func=test, args=(i,)) ##同步接口
pool.apply_async(func=test, args=(i,), callback = Fd) ##回调
pool.close()
pool.join()
print("END......")
协程 (微线程)
yield
import time
import queue
def consumer(name):
print("--->ready to eat baozi...")
while True:
new_baozi = yield ##在此处卡住,知道另外线程发送send
print("[%s] is eating baozi %s" % (name,new_baozi))
def producer():
r = con.__next__() ##运行consumer
r = con2.__next__()
n = 0
while 1:
time.sleep(1)
print("producer is making baozi %s and %s" %(n,n+1) )
con.send(n) ##send,传递资源
con2.send(n+1)
n +=2
if __name__ == '__main__':
con = consumer("c1")
con2 = consumer("c2")
p = producer()
Greenlet
from greenlet import greenlet
def quest_foo():
print("你好!")
answ_foo.switch() ##switch()主管切换功能
print("再见!")
answ_foo.switch()
def answ_foo():
print("你好!")
quest_foo.switch()
print("再见!")
if __name__ == "__main__":
quest_foo = greenlet(quest_foo)
answ_foo = greenlet(answ_foo)
answ_foo.switch()
Python并发式编程的更多相关文章
- 【转载】Stackless Python并发式编程介绍[已校对版]
Stackless Python并发式编程介绍[已校对版] 作者: Grant Olson 电子邮件: olsongt@verizon.net 日期: 2006-07-07 译者: ...
- Python 黑帽编程大纲(变化中)
Python 黑帽编程大纲(预览版) 教程说明: 本系列教程,采用的大纲母本为<Understanding Network Hacks Attack and Defense with Pytho ...
- Python黑帽编程 3.4 跨越VLAN
Python黑帽编程 3.4 跨域VLAN VLAN(Virtual Local Area Network),是基于以太网交互技术构建的虚拟网络,既可以将同一物理网络划分成多个VALN,也可以跨越物理 ...
- Python黑帽编程1.1虚拟机安装和配置 Kali Linux 2016
Python黑帽编程1.1虚拟机安装和配置 Kali Linux 2016 0.1 本系列教程说明 本系列教程,采用的大纲母本为<Understanding Network Hacks Att ...
- Python黑帽编程1.2 基于VS Code构建Python开发环境
Python黑帽编程1.2 基于VS Code构建Python开发环境 0.1 本系列教程说明 本系列教程,采用的大纲母本为<Understanding Network Hacks Atta ...
- Python黑帽编程1.3 Python运行时与包管理工具
Python黑帽编程1.3 Python运行时与包管理工具 0.1 本系列教程说明 本系列教程,采用的大纲母本为<Understanding Network Hacks Attack and ...
- PYTHON黑帽编程1.5 使用WIRESHARK练习网络协议分析
Python黑帽编程1.5 使用Wireshark练习网络协议分析 1.5.0.1 本系列教程说明 本系列教程,采用的大纲母本为<Understanding Network Hacks At ...
- Python黑帽编程 2.0 第二章概述
Python黑帽编程 2.0 第二章概述 于 20世纪80年代末,Guido van Rossum发明了Python,初衷据说是为了打发圣诞节的无趣,1991年首次发布,是ABC语言的继承,同时也是一 ...
- Python黑帽编程2.1 Python编程哲学
Python黑帽编程2.1 Python编程哲学 本节的内容有些趣味性,涉及到很多人为什么会选择Python,为什么会喜欢这门语言.我带大家膜拜下Python作者的Python之禅,然后再来了解下P ...
随机推荐
- 你真的了解webview么?
你真的了解webview么? 写在前面: Webview是我们前端开发从PC端演进到移动端的一个重要载体,现在大家每天使用的App,webview都发挥着它的重要性.接下来让我们从webview看世界 ...
- 3.Flask-SQLAlchemy
(1)安装 pip install flask_sqlalchemy (2)数据库连接 from flask import Flask # 1.导入 from flask_sqlalchemy imp ...
- 【WebGIS系列】Typescript+WebGL+Webpack开发环境搭建
目前Web实现矢量渲染的主流技术包括SVG.VML和WebGL.相对而言,VML是一种较古老的技术,虽然未成为W3C标准,但被早期的IE浏览器(IE9以下)和微软Office广泛使用,目前已经远离了浏 ...
- 写给 Android 开发的小程序布局指南,Flex 布局!
一.序 Hi,大家好,我是承香墨影! 最近在做小程序,验证一些方向,开发效率确实很快,就是各种微信的审核有点费劲,但是总归是有办法解决的. 想要开发一款小程序,其实和我们正常写一款 App 类似,你需 ...
- BaiduSpeechDemo【百度语音SDK集成】(基于v3.0.7.3)
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 本Demo将百度语音SDK(其中一部分功能)和自定义的UI对话框封装到一个module中,便于后续的SDK版本更新以及调用. 本De ...
- Elasticsearch之索引模板index template与索引别名index alias
为什么需要索引模板? 在实际工作中针对一批大量数据存储的时候需要使用多个索引库,如果手工指定每个索引库的配置信息(settings和mappings)的话就很麻烦了. 所以,这个时候,就存在创建索引模 ...
- 值得一看的35个Redis常用问题总结
1.什么是redis? Redis 是一个基于内存的高性能key-value数据库. 2.Reids的特点 Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库 ...
- Git 安装配置手册
Git 安装配置手册 首先我们要了解 Git 是类似于 SVN 用来管理项目的 首先要先下载 Git ,这个东西相当于一个核,是该功能的核心 下载地址(<https://gitforwindow ...
- PHP八大设计模式
设计模式 单例模式解决的是如何在整个项目中创建唯一对象实例的问题,工厂模式解决的是如何不通过new建立实例对象的方法. 单例模式 $_instance必须声明为静态的私有变量 构造函数和析构函数必须声 ...
- Cookie 数据浅谈
Cookie 是一些数据, 存储于你电脑上的文本文件中. 当 web 服务器向浏览器发送 web 页面时,在连接关闭后,服务端不会记录用户的信息. Cookie 的作用就是用于解决 "如 ...