Python 语法基础 线程 进程 协程
文章目录
一 线程
1创建线程
from threading import Thread#导入线程模块
import time#导入时间模块
li = []
#写入数据
def wdata():
for i in range(5):
li.append(i)
time.sleep(1)
print("写入的数据是",li)
#读取数据
def rdata():
print("读取的数据是",li)
if __name__ == '__main__':
#创建子线程
t1 = Thread(target=wdata)
t2 = Thread(target=rdata)
#开启子线程
t1.start()
t2.start()
2阻塞线程
if __name__ == '__main__':
#创建子线程
t1 = Thread(target=fun1)
t2 = Thread(target=fun2)
#开启子线程
t1.start()
t1.join()#阻塞主线程,直到t1完成
t2.start()
t2.join()#阻塞主线程,直到t2完成
3互斥锁
当一个锁执行时,另一个线程也要使用同一个锁,将会等待锁执行完成
加锁后必须解锁
lock = Lock()#声明锁 必须是公共变量
lock.acquire()#加锁
#代码块
lock.release()#解锁
from threading import Thread,Lock#导入锁
import time
a = 0
b = 2000000
lock = Lock()#声明锁
#写入数据
def funa():
lock.acquire()#加锁
for i in range(b):
global a
a+=1
print("方法1a的值",a)
lock.release()#解锁
#读取数据
def funb():
lock.acquire()
for i in range(b):
global a
a += 1
print("方法2a的值", a)
lock.release()
if __name__ == '__main__':
#创建子线程
t1 = Thread(target=funa)
t2 = Thread(target=funb)
#开启子线程
t1.start()
t2.start()
二 线程
1常用成员
py提供了Process类代表进程对象
Process类构造参数
target:执行的任务名称,即子进程要执行的任务
args 用元组形式传参
kwargs 用字典形式传参
方法
start() 开启子进程
isAlive() 子进程是否还活着
join() 主进程等待子进程执行结束,阻塞
属性
name 进程的名字 默认Process-N N是从递增的数字
pid 进程号
2启动一个进程
from multiprocessing import Process#导入模块
def sing():
print('sing')
def dance():
print('dance')
if __name__ == '__main__':
#创建子进程
p1 = Process(target=sing)#定义进程
p2 = Process(target=dance)
p1.start()#开启进程 打印sing
p2.start()#dance 打印dance
print("p1",p1.name)#p1 Process-1 比sing和dance的打印先执行
print("p2",p2.name)#p2 Process-2 比sing和dance的打印先执行
3 进程的名字
默认名字是 Process-N
p1 = Process(target=sing)#分配默认名字
p1.start()#开启进程 打印sing
print("p1",p1.name)#p1 Process-1 比sing的打印先执行
定义自定义名字
p1 = Process(target=sing,name="我喜欢唱歌")#创建时自定义名字
p1.start()#开启进程 打印sing
print("p1",p1.name)#p1 我喜欢唱歌 比sing的打印先执行
#也可以用对象改
p1.name="我的名字"
4 进程的编号
获取子进程编号
p1 = Process(target=sing)
p1.start()
print("p1",p1.pid)#p1 44956
获取当前进程和父进程的编号
from multiprocessing import Process
import os#导入os模块来获取当前的进程号
def sing():
print('sing的pid',os.getpid())
print("sing的父进程pid",os.getppid())
if __name__ == '__main__':
p1 = Process(target=sing)
p1.start()
print("python程序的Pid",os.getpid())
输出结果
5 启动进程时传参
from multiprocessing import Process
def eat(name):
print('eat', name)
if __name__ == '__main__':
p = Process(target=eat, args=("xiaoming",))#注意单参数元组必须加逗号
p.start()#eat xiaoming
6 子进程存活监测与阻塞
from multiprocessing import Process
def eat(name):
print('eat', name)
if __name__ == '__main__':
p = Process(target=eat, args=("xiaoming",))
p.start()
print(p.is_alive()) #永远是存活,因为这里先执行,子进程会稍后执行
from multiprocessing import Process
def eat(name):
print('eat', name)
if __name__ == '__main__':
p = Process(target=eat, args=("xiaoming",))
p.start()
p.join()#使用join,主进程会等子进程执行完毕再执行
print(p.is_alive())#False 结果永远是false
7 进程之间的通信
和线程不同,进程之间无法共享全局变量
7.1队列
常用方法
put()添加 先入先出,如果已经满了还加,程序会阻塞永远卡死
get()取出
empty()是否为空
full()是否已经满了
size()当前还有多少数据没取
from queue import Queue#引入模块
q = Queue(3)#指定队列长度,空或者负值代表没有上限
q.put(1)#加入一条数据
q.put("第二条数据")
q.put("第三条数据")
print(q.get())#1 取出消息后,第一条会移除
print(q.get())#第二条数据
print(q.empty())#False
7.2 进程使用队列跨进程通信
必须使用进程模块提供的Queue类才能跨进程通信,普通的Queue类无法跨进程
from multiprocessing import Process,Queue
正常情况下进程之间不会共享任何数据
from multiprocessing import Process,Queue
li = []
def wData():
global li
for i in range(5):
li.append(i)
print("写入",li)
def rData():
global li
print("读取",li)
if __name__ == '__main__':
p1 = Process(target=wData)
p2 = Process(target=rData)
p1.start()#写入 [0, 1, 2, 3, 4]
p2.start() #读取 []
使用Queue可以跨进程传递数据
from multiprocessing import Process,Queue
def wData(q):
for i in range(5):
q.put(i)
print("写入",i)
def rData(q):
while True:
if q.empty():
break
else:
print("读取",q.get())
if __name__ == '__main__':
q = Queue()#注意队列必须声明在这个if下,不能放在最外层
p1 = Process(target=wData, args=(q,))
p2 = Process(target=rData, args=(q,))
p1.start()#写入0 写入1 写入2 写入3 写入4
p1.join()
p2.start() #读取0 读取1 读取2 读取3 读取4
三 协程
1 定义
生成器就是协程
def myCoroutine():#一个普通方法,带yield自动识别为协程
yield "a"
yield "b"
yield "c"
g = myCoroutine()#协程对象
print(next(g))#a 使用next执行下一个yield
print(next(g))#b
print(next(g))#c
常用于IO操作 如文件读写 网络请求
2 Greenlet
第三方模块,封装了协程,可以手动切换正在执行的任务
2.1安装
注意如果使用pycharm编辑,会自动给项目创建一个虚拟环境,如果使用windows的cmd会导致安装环境不一致,所以要用pycharm的控制台
安装命令:
pip install greenlet 或 python -m pip install greenlet
卸载
pip uninstall greenlet
查看安装路径
pip show greenlet
2.2 使用
基础
from greenlet import greenlet#引入模块
#这是两个普通的方法,并非生成器
def sing():
print("在唱歌")
print("唱完了")
def dance():
print("在跳舞")
print("跳完了")
if __name__ == "__main__":
g1 = greenlet(sing)
g2 = greenlet(dance)
g1.switch()#在唱歌 唱完了 只有见到switch才会执行
g2.switch()#在跳舞 跳完了
任务间切换
from greenlet import greenlet#引入模块
#这是两个普通的方法,并非生成器
def sing():
print("在唱歌")
g2.switch() #在这里将任务切换到别的方法
print("唱完了")
def dance():
print("在跳舞")
print("跳完了")
if __name__ == "__main__":
g1 = greenlet(sing)
g2 = greenlet(dance)
g1.switch()#在唱歌 在跳舞 跳完了 执行sing的方法,遇到g2.switch()切换到dance,执行完dance
g1.switch()#唱完了 #然后继续执行剩下的sing
3 Gevent
和greenlet类似,但是他遇到IO操作时,会自动切换程序
gevent基于greenlet
3.1安装与卸载
注意如果使用pycharm编辑,会自动给项目创建一个虚拟环境,如果使用windows的cmd会导致安装环境不一致,所以要用pycharm的控制台
安装命令:
python -m pip install gevent
3.2 常用函数
gevent.spawn(函数名) 创建协程对象
gevent.sleep() 协程等待,类似time.sleep,gevent中必须用geven.sleep
gevent.join() 阻塞,等待某个协程执行结束
gevent.joinall() 等待所有协程对象都执行结束再退出,参数是一个协程对象列表
使用实例1 这里没有任何耗时操作,只是为了辅助理解调度池
import gevent
def sing():
print("在唱歌")
print("唱完了")
def dance():
print("在跳舞")
print("跳完了")
if __name__ == '__main__':
#创建协程对象 将协程对象自动放入调度池,但不会执行
g1 = gevent.spawn(sing)
g2 = gevent.spawn(dance)
g2.join()#等待g2执行结束 join的作用是阻塞主线程并等待协程执行完毕 协程会按加入调度池的顺序依次执行 打印结果为 在唱歌 唱完了 在跳舞 跳完了
使用实例2
import gevent
def sing():
print("在唱歌")
gevent.sleep(1)#注意不能用time.sleep
print("唱完了")
def dance():
print("在跳舞")
gevent.sleep(3)
print("跳完了")
if __name__ == '__main__':
#创建协程对象 将协程对象自动放入调度池,但不会执行
g1 = gevent.spawn(sing)
g2 = gevent.spawn(dance)
g2.join()#打印结果 在唱歌 在跳舞 唱完了 没有跳完了 因为程序先执行g1,遇到sleep切换到g2,g1g2的睡眠同步计时,但是g1只睡1秒,g2来不及执行,此时程序已经退出 如果想让g2完整执行,需要加上g2.join()
使用实例 3 joinall的使用,等所有协程执行完
import gevent
def sing():
print("在唱歌")
gevent.sleep(1)#注意不能用time.sleep
print("唱完了")
def dance():
print("在跳舞")
gevent.sleep(3)
print("跳完了")
if __name__ == '__main__':
#创建协程对象 将协程对象自动放入调度池,但不会执行
g1 = gevent.spawn(sing)
g2 = gevent.spawn(dance)
gevent.joinall([g1, g2])#打印结果 在唱歌 在跳舞 (一秒后)唱完了 (2秒后)跳完了
使用实例 4 传参
def sing(name):
print(f"{name}在唱歌")
gevent.sleep(1)#注意不能用time.sleep
print("唱完了")
g1 = gevent.spawn(sing,"我的名字")
3.3 Monkey 补丁
在模块运行时可以将原本的time.sleep 替换为gevent.sleep
from gevent import mokey
monkey.patch_all()#必须放在前边 ,运行时会自动把time.sleep替换为gevent.sleep
def sing(name):
print(f"{name}在唱歌")
time.sleep(1)
print("唱完了")
更多推荐


所有评论(0)