进程锁
# 锁在IT界很重要,不但在Python中出现,尤其是数据库中得锁更多,比如:表锁、行锁、 悲观锁、乐观锁、进程锁、互斥锁、递归锁、可重入锁、死锁等
# 保证安全
import time # 导入time,执行顺序乱了 from multiprocessing import Process, Lockdef task(i, lock): # 上一把锁 lock.acquire()print("进程%s来了" % i)time.sleep(1)print("进程%s走了" % i) lock.release() # 释放锁"""只要你上了锁,一定别忘了最后释放锁,否则的话,别的进程永远进不来"""if __name__ == '__main__':lock=Lock() # 得到一把锁for i in range(3):p = Process(target=task, args=(i+1, lock))p.start()
# 同一时刻只有一个进程拿到这把锁,释放后下一个进程才会拿
# 加锁虽然保证了数据的安全,执行的效率一定是降低了
# 该加锁一定要加
如何查看进程号
p.pid() 子进程的进程号
import time,os from multiprocessing import Process, Lockdef task():print("task进程的进程号:", os.getpid()) print("task进程的父进程的进程号:", os.getppid()) # parent processtime.sleep(20) if __name__ == '__main__':p=Process(target=task, )p.start()print('子进程的进程号:', p.pid)print("主进程的进程号", os.getpid())time.sleep(10)
"""有了进程号,我们就可以通过进程号来结束进程的执行 kill 9176 kill -9 9176"""
# os.getpid() 写在哪个进程里面就会输出哪个进程的进程号
# taskkill / pid 9176 相当于手动结束命令
进程之间数据隔离问题
# 进程1中的a和进程2中的a完全不一样,且不能相互使用
n=100 # 主进程n还是不变 def task():global nn=1 # 改的子进程中的n
# 进程与进程之间数据如何通信?
队列(Queue)
数据结构:链表、单链表、双链表、循环链表、栈、队列、树、二叉树、图
队列特点: 先进先出
栈的特点:先进后出 python给我们提供了一个内置的队列类
from multiprocessing import Queue q=Queue(3) # 超过3个会阻塞,等出一个再进 q.put('hello') q.put('world') # 入队:往队列里面添加数据 print(q.get()) # hello print(q.get()) # world 出队:从队列里面取出值
q.put(self, obj, block=True, timeout=None)
# block=False: 队列放不进数据时,会立马报错
# timeout=3:超时的时间, 如果在指定的时间内,没有放进去,就会直接报错
q.put_nowait(self,obj): # 值放不进去会直接报错return self.put(obj,False)
print(q.get())
print(q.get()) # 三个数都取出来了
print(q.get())print(q.get()) # 第四个会阻塞等待put输值
q.get() 和q.put用法一样 q.get_nowait()
print(q.qsize()) # 取值完为0,还剩一个没取的就是1 print(q.empty()) # 看这个队列里还有没有数据 T/F print(q.full()) # 看队列是否满不满 T/F
# 队列里面的数据在内存中存着的
# 专业的消息队列:kafka, rabbitmq等,他们能够解决特殊场景的问题
生产者消费者模型(重要)
# 在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题
通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度
# 通过一个容器来解决强耦合问题,生产者和消费者不直接进行通讯
def producer():for i in range(10):q.put("生产的第%s个包子" % i) # 放队列 def consumer():while True:res = q.get() # 取队列,队列没有东西会一直等待print(res)if res is None:break from multiprocessing import Prscess, Queue if __name__ == '__main__':p = Process(target= producer) # 生产者p.sart()c = Process(target= consumer) # 消费者c.start()
# 改良版本:在生产完后放一个标志位,当取到标志位,break结束
线程
# 在一个进程中,线程就是必须存在的,至少要有一个线程来执行任务
# 一个进程中可以有多个线程
# 进程和线程都是有操作系统调度的
# 进程是操作系统分配资源的基本单位,线程是操作系统执行的最小单位
开启线程:
from threading import Thread def task(a, b):pass if __name__ == '__main__':t=Thread(target=task, name='Thread-2', args=('a', ), kwargs={'b':1})t.daemon = True # 把该线程设置为守护线程, 主线程执行完毕,子线程也结束t.start()
# 一个进程中如果只有一个线程,该线程称之为是主线程,其他线程称之为是子线程
本身有一个主线程,def task是主线程拉起的一个子线程
# 先子线程后主线程,和进程相反
开线程的资源特别小,会立刻执行
t.join() 确保子先后主
# 守护线程:主线结束,子进程立刻结束
t.is_alive() t.setName('aaaa') # 改名字 t.getName('aaaa') t.join() t.start() # 与进程用法一样 t.daemon = True t.setDaemon(True) # 守护线程 threading.currentThread() # 当前线程的对象 threading.enumerate() # 返回正在运行的线程对象列表 threading.activeCount() # 正在运行的线程数量
进程和线程的比较:
1、进程的开销比线程的开销大很多
2、进程之间的数据是隔离的,但是,线程直接的数据不隔离
3、多个进程之间的线程数据不共享--->还是让进程通信(IPC)--->进程下的线程也通信--->队列