首页 / PYTHON / python实现并发学习笔记
python实现并发学习笔记
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了python实现并发学习笔记,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含8959字,纯文字阅读大概需要13分钟。
内容图文
![python实现并发学习笔记](/upload/InfoBanner/zyjiaocheng/847/dd0fc496b69942fbac05640aef01b35d.jpg)
多进程
- 进程:正在进行的过程或者说是一个任务,而负责执行任务则是cpu
- 同一个程序执行两次是两次进程
- 并发:
- 并行:基于多核cpu
unix开子进程的拷贝一份父进程的数据
进行的三个状态:运行,阻塞,就绪
在python中如何开启子进程
- multiprocessing模块中的process类
# 方式1
from multiprocessing import Process
import time
def task(name):
print('%s is running'%name)
time.sleep(5)
print('%s is done'%name)
if __name__ =='__main__':
p = Process(target=task,args=('子进程1',))
p.start() #仅仅只是给操作系统发送了一个信号
#方式二:自定义类继承自process
from multiprocessing import Process
import time
class MyProcess(Process):
def __init__(self,name):
super().__init__()
self.name = name
def run(self): #函数名必须是run
print('%s is running'%self.name)
time.sleep(5)
print('%s is done'%self.name)
if __name__ == '__main__':
p = MyProcess('子进程1')
p.start()#本质就是在调用p.run
print('进')
查看进程的pid与ppid(进程id)
- 补充:
- windows查看正在执行的进程:tasklist | findstr pycharm
- Mac os查看正在执行的进程:ps aus|grep pycharm
from multiprocessing import Process
import time
import os
def task(name):
print('%s is running,parent id is <%s>'%(os.getpid(),os.getppid()))
time.sleep(5)
print('%s is done'%os.getpid())
if __name__ =='__main__':
p = Process(target=task,args=('子进程1',))
p.start() #仅仅只是给操作系统发送了一个信号
print('主',os.getpid())
process对象的其他属性或方法
- join()等子进程结束完毕才会继续运行主进程,主进程结束后所有的僵尸进程结束
- start()只是向操作系统发送信号,并不只是把进程立马开起来,如果连续有几个start有可能执行的先后顺序会错乱,如果start方法后面立马接一个join,多个子进程会变成串行
- is_alive()查看子进程时候已经结束
- terminate()杀死这个子进程
- pid()查看进程id
- name()查看这个对象的名字
守护进程
- 当主进程执行结束子进程跟着结束:将daemon属性设置为true,守护进程不能有子进程。代码执行到程序最后一行代表程序运行结束
互斥锁
- 把并发变成串行:使用multiprocessing模块下的Lock对象
#牺牲效率实现子进程串行
from multiprocessing import Process,Lock
import time
def tack(name,lock):
lock.acquire()#加锁
print('%s,1'%name)
time.sleep(1)
print('%s,2'%name)
time.sleep(1)
print('%s,3'%name)
lock.release()#释放锁
if __name__ == '__main__':
lock = Lock()#实例化锁对象
for i in range(3):
p = Process(target=tack,args=('进程%s'%i,lock))#把锁传到子进程中
p.start()
互斥锁与join的区别:join确实能实现代码串行,但join把整个代码变成串行,但互斥锁可以把部分代码变成串行
队列
multiprocessing有提供基于ipc通信类
from multiprocessing import Queue
q = Queue(4)#指定队列大小,如果不指定大小则大小为无穷尽
q.put('hello')#插入数据到队列中
print(q.full())#判断队列中数据是否满了
q.get()#从队列读取并删除一个数据
print(q.empty())#判断队列中数据是否空了
- 生产者消费这模型:
- 生产者:生产数据任务
- 消费者:消费数据任务
from multiprocessing import Process,Queue
import time
def producer(q):
for i in range(3):
res = '包子%s'%i
time.sleep(0.5)
q.put(res)
print('生产者生产了%s'%res)
def consumer(q):
while True:
res = q.get()
if res == None:break
time.sleep(0.7)
print('消费者吃了%s'%res)
if __name__ == '__main__':
q = Queue()
p1 = Process(target=producer,args=(q,))
c1 = Process(target=consumer,args=(q,))
p1.start()
c1.start()
p1.join()
c1.join()
q.put(None)
- JoinableQueue:与Queu使用一样,只不过可以使用join方法
多线程
- 线程之间的数据是共享的
如何开启线程
- threading模块(使用方法与multiprose一样)
import time
import random
from threading import Thread
def run(name):
print('%s is running'%name)
time.sleep(random.randrange(1,5))
print('%s is end'%name)
if __name__ == '__main__':
t1 = Thread(target=run,args=('喵',))
t1.start()
print('主线程')
import time
from threading import Thread
class MyThread(Thread):
def __init__(self,name):
super().__init__()
self.name = name
def run(self):
print('%s is running'%self.name)
time.sleep(2)
print('%s is end'%self.name)
if __name__ == '__main__':
t1 = MyThread('喵')
t1.start()
print('主线程')
thread对象的其他属性与方法
from threading import Thread,currentThread,active_count,enumerate
import time
def task():
print('%s is running'%currentThread().getName())
time.sleep(2)
print('%s is done'%currentThread().getName())
if __name__ == '__main__':
t = Thread(target=task,name='子线程')
t.start()
#t.setName('儿子进程1') 设置线程名字
print(t.isAlive())#判断线程是否存活
print('主线程',currentThread().getName())
# t.join()#等当前线程结束才继续执行主线程
print(active_count()) #活跃的线程数
print(enumerate())#[<_MainThread(MainThread, started 140735697388416)>, <Thread(子线程, started 123145519529984)>]
守护线程
- 在一个进程内,只有一个线程,线程运行结束,代表这个一个进程结束。
- 在一个进程内,开多个线程,主线程在代码运行完毕,还需要等待其他线程干完活才会结束
互斥锁
- 将并行编程串行,牺牲效率保证数据安全,与进程的互斥锁一样使用
GIL全局解释器锁
死锁与递归锁
- 互斥锁只能acquire一次
from threading import Thread,Lock
import time
mutexA = Lock()
mutexB = Lock()
class MyThread(Thread):
def run(self):
self.f1()
self.f2()
def f1(self):
mutexA.acquire()
print('%s 拿到了A锁'%self.name)
mutexB.acquire()
print('%s 拿到了B锁'%self.name)
mutexB.release()
mutexA.release()
def f2(self):
mutexB.acquire()
print('%s 拿到了B锁' % self.name)
time.sleep(0.1)
mutexA.acquire()
print('%s 拿到了A锁' % self.name)
mutexA.release()
mutexB.release()
for i in range(10):
t = MyThread()
t.start()
- 递归锁:可以acquire多次,每次acquire一次计数器+1,只要计数为0,才能被其他线程抢到
# 递归锁
from threading import Thread,RLock
import time
mutexA = mutexB = RLock()
class MyThread(Thread):
def run(self):
self.f1()
self.f2()
def f1(self):
mutexA.acquire()
print('%s 拿到了A锁'%self.name)
mutexB.acquire()
print('%s 拿到了B锁'%self.name)
mutexB.release()
mutexA.release()
def f2(self):
mutexB.acquire()
print('%s 拿到了B锁' % self.name)
time.sleep(0.1)
mutexA.acquire()
print('%s 拿到了A锁' % self.name)
mutexA.release()
mutexB.release()
for i in range(10):
t = MyThread()
t.start()
信号量:可以同时运行多个线程
from threading import Thread,Semaphore,currentThread
import time,random
sm = Semaphore(3)
def task():
with sm:
print('%s is run'%currentThread().getName())
time.sleep(random.randint(1,3))
if __name__ == '__main__':
for i in range(10):
t = Thread(target=task)
t.start()
Event事件:实现线程同步
- event.wait()#等待(可设置等待时间)
- event.set()#开始
- event.is_set()
from threading import Thread,Event
import time
event = Event()
def student(name):
print('学生 %s正在听课'%name)
event.wait()
print('学生%s下课了'%name)
def teacher(name):
print('老师%s 正在上课'%name)
time.sleep(7)
print('老师%s 让学生下课了'%name)
event.set()
if __name__ == '__main__':
s1 = Thread(target=student,args=('wualin',))
s2 = Thread(target=student,args=('wxx',))
s3 = Thread(target=student,args=('zxx',))
t1 = Thread(target=teacher,args=('egon',))
s1.start()
s2.start()
s3.start()
t1.start()
定时器
线程queue
- 先进先出
import queue
q = queue.Queue(3) #先进先出->队列
q.put(5)
q.put('miao')
q.put('sta')
print(q.get())
print(q.get())
print(q.get())
#get 和 put可设置是否阻塞以及阻塞时间
print(q.get(block=True,timeout=3))
- 后进先出
q = queue.LifoQueue(3)#后进先出->堆栈
q.put('fisrt')
q.put(2)
q.put('miao')
print(q.get())
print(q.get())
print(q.get())
- 优先级队列
import queue
q = queue.PriorityQueue(3)#优先级队列
q.put((10,'one'))
q.put((40,'two'))
q.put((20,'three'))
#数字越小优先级越高
print(q.get())
print(q.get())
print(q.get())
进程池与线程池
- 池对线程或进程数量进行一个限制
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
import os,time,random
def task(name):
print('name:%s pid:%s run'%(name,os.getpid()))
time.sleep(random.randint(1,3))
if __name__ == '__main__':
pool = ProcessPoolExecutor(4)#进程池
for i in range(10):
pool.submit(task,'egon%s'%i)#异步调用
pool.shutdown()#把往进程池提交任务的入口关闭
print('主')
异步调用与回调机制
- 提交任务的两种方式
同步调用:提交完任务后,就在原地等待任务执行完毕,拿到结果再执行下一行代码,程序是串行执行
异步调用
from concurrent.futures import ThreadPoolExecutor
import time,random
def eat(name):
print('%s is eating'%name)
time.sleep(random.randint(2,5))
res = random.randint(5,10)*'#'
return {'name':name,'size':res}
def count(weith):
weith = weith.result()#
name = weith['name']
size = len(weith['size'])
print('name:%s eat is %s'%(name,size))
if __name__ == '__main__':
pool = ThreadPoolExecutor(5)
pool.submit(eat,'miao').add_done_callback(count)#回调机制
pool.submit(eat,'car').add_done_callback(count)
pool.submit(eat,'dog').add_done_callback(count)
pool.submit(eat,'zhang').add_done_callback(count)
协程
- 单线程下实现并发,在应用程序层次实现并发效果
greenlet模块
- 在多个任务之间自由切换,但是不能检测io,比yield封装程度更高
from greenlet import greenlet
def eat(name):
print('%s eat 1'%name)
g2.switch('miao')
print('%s eat 2'%name)
g2.switch('miao')
def play(name):
print('%s play 1'%name)
g1.switch()
print('%s play 2'%name)
g1 = greenlet(eat)
g2 = greenlet(play)
g1.switch('miao')
>>>miao eat 1
>>>miao play 1
>>>miao eat 2
>>>miao play 2
gevent
import gevent
import time
from gevent import monkey
monkey.patch_all()#给IO打补丁,碰到IO就切换任务
def eat(name):
print('%s eat 1'%name)
gevent.sleep(3)
print('%s eat 2'%name)
def play(name):
print('%s play 1'%name)
gevent.sleep(4)
print('%s play 2'%name)
g1 = gevent.spawn(eat,'miao')
g2 = gevent.spawn(play,'alex')
#遇到io切换任务
g1.join()#异步提交任务,保证所有进程执行完才结束
g2.join()
gevent.joinall([g1,g2])#和上面的join一样
I/O模型
内容总结
以上是互联网集市为您收集整理的python实现并发学习笔记全部内容,希望文章能够帮你解决python实现并发学习笔记所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。