一知半解的人,多不谦虚;见多识广有本领的人,一定谦虚。
1 开启进程的两种方式
2 进程对象其他属性和方法:
-pid进程id号,os.getpid()
-ppid:父进程id号,os.getppid()
-is_alive():当前进程是否存活
-terminate():关闭当前进程
3 守护进程
-父进程结束,子进程也跟着结束
-t.daemon=True
4 进程间数据隔离
-进程之前的数据是独有的,不同进程间不能相互使用
5 队列
-Queue:实现进程间通信,同一台及其上的不同进程
-q=Queue(数字)
-q.put()
-q.get()
-如果队列为空,取不到会阻塞
-如果队列满了,放不进去,会阻塞
6 进程间通信IPC机制
-在一条进程中放到queue中值
-在另一条进程中取出值
7 进程互斥锁
-为了防止多进程操作同一个数据(文件),数据写乱了的问题
-要在进程写数据的时候加锁,并行变成串行,牺牲了效率,保证了安全
-mutex=Lock()
-mutex.acquire()
-mutex.release()
--补充:分布式锁,悲观锁,乐观锁
今日内容
1 生产者消费者模型
# 1 理论:
-生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。
-生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取
-阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力
# 2 代码实现
# 初级生产者消费者模型
# import time
# import random
# from multiprocessing import Process, Queue
#
#
# def producer(name, food, q):
# for i in range(10):
# data = '%s 制造了%s' % (name, food)
# # 模拟制造食物延迟
# time.sleep(random.randint(1, 3))
# print(data)
# q.put(food)
#
#
# def consumer(name, q):
# while True:
# food = q.get()
# # 模拟吃食物延迟
# time.sleep(random.randint(1, 3))
# print('%s消费了%s' % (name, food))
#
#
# if __name__ == '__main__':
# q = Queue()
# # 创造一个生产者
# p = Process(target=producer, args=('egon', '包子', q))
# p.start()
#
# # 创造一个消费者
# c = Process(target=consumer, args=('鸡哥', q))
# c.start()
# 如果queue中没有数据了,消费者会一直卡住
# import time
# import random
# from multiprocessing import Process, Queue
#
# def producer(name, food, q):
# for i in range(10):
# data = '%s 制造了%s' % (name, food)
# # 模拟制造食物延迟
# time.sleep(random.randint(1, 3))
# print(data)
# q.put(food)
# q.put(None)
#
#
# def consumer(name, q):
# while True:
# food = q.get()
# if food is None:return # 当队列中取出None,之间结束
# # 模拟吃食物延迟
# time.sleep(random.randint(1, 3))
# print('%s消费了%s' % (name, food))
#
#
# if __name__ == '__main__':
# q = Queue()
# # 创造一个生产者
# p = Process(target=producer, args=('egon', '包子', q))
# p.start()
#
# # 创造一个消费者
# c = Process(target=consumer, args=('鸡哥', q))
# c.start()
# # 制造两个消费者
# import time
# import random
# from multiprocessing import Process, Queue
#
# def producer(name, food, q):
# for i in range(10):
# data = '%s 制造了%s' % (name, food)
# # 模拟制造食物延迟
# time.sleep(random.randint(1, 3))
# print(data)
# q.put(food)
#
#
# def consumer(name, q):
# while True:
# food = q.get()
# if food is None:return # 当队列中取出None,之间结束
# # 模拟吃食物延迟
# time.sleep(random.randint(1, 3))
# print('%s消费了%s' % (name, food))
#
#
# if __name__ == '__main__':
# q = Queue()
# # 创造一个生产者
# p = Process(target=producer, args=('egon', '包子', q))
# p.start()
#
# # 创造一个消费者
# c = Process(target=consumer, args=('鸡哥', q))
# c.start()
# c1 = Process(target=consumer, args=('王铁蛋', q))
# c1.start()
# # 生产者生产完毕,放两个None
# p.join() # 等待p进程执行完成再放
# q.put(None)
# q.put(None)
# 多个生产者和多个消费者
# 制造两个消费者
# import time
# import random
# from multiprocessing import Process, Queue
#
# def producer(name, food, q):
# for i in range(10):
# data = '%s 制造了%s' % (name, food)
# # 模拟制造食物延迟
# time.sleep(random.randint(1, 3))
# print(data)
# q.put(food)
#
#
# def consumer(name, q):
# while True:
# food = q.get()
# if food is None:return # 当队列中取出None,之间结束
# # 模拟吃食物延迟
# time.sleep(random.randint(1, 3))
# print('%s消费了%s' % (name, food))
#
#
# if __name__ == '__main__':
# q = Queue()
# # 创造一个生产者
# p = Process(target=producer, args=('egon', '包子', q))
# p.start()
#
# p1 = Process(target=producer, args=('alex', '泔水', q))
# p1.start()
# # 创造一个消费者
# c = Process(target=consumer, args=('鸡哥', q))
# c.start()
# c1 = Process(target=consumer, args=('王铁蛋', q))
# c1.start()
# c2 = Process(target=consumer, args=('李铁柱', q))
# c2.start()
# # 生产者生产完毕,放两个None
# p.join() # 等待p进程执行完成再放
# p1.join() # 等待p1(另一个生产者)进程执行完成再放
#
# q.put(None)
# q.put(None)
# q.put(None)
# 最终版本,不用放None
import time
import random
from multiprocessing import Process, Queue,JoinableQueue
def producer(name, food, q):
for i in range(10):
data = '%s 制造了%s' % (name, food)
# 模拟制造食物延迟
time.sleep(random.randint(1, 3))
print(data)
q.put(food)
def consumer(name, q):
while True:
food = q.get()
# 模拟吃食物延迟
time.sleep(random.randint(1, 3))
print('%s消费了%s' % (name, food))
q.task_done() # 把队列中维护的数字减一
if __name__ == '__main__':
# q = Queue()
# 内部为何了一个数字,放一个数字会加一
# 消费一个数字减一
q = JoinableQueue()
# 创造一个生产者
p = Process(target=producer, args=('egon', '包子', q))
p.start()
p1 = Process(target=producer, args=('alex', '泔水', q))
p1.start()
# 创造一个消费者
c = Process(target=consumer, args=('鸡哥', q))
# c.daemon = True
c.start()
c1 = Process(target=consumer, args=('王铁蛋', q))
# c1.daemon = True
c1.start()
c2 = Process(target=consumer, args=('李铁柱', q))
# c2.daemon = True
c2.start()
# 主结束,消费进程也结束,把每个消费进程都设置成守护进程
# 等待所有生产者生产结束,主进程再结束
p.join()
p1.join()
q.join() # 会卡再者,一直等待q队列中数据没有了,才继续往下走
print('生产者结束了,主进程结束')
# JoinableQueue()
# 每放一个值,数字加一
# 取值不会减一,q.task_done()
# q.join() 一直阻塞,当q没有值了,才继续走
2 线程理论
# 计算机相当于大工厂,工厂里有一个个的车间(进程),有很多人(线程)干不同的事
# 真正干活的是线程--》线程是cup调度的最小单位
# 进程是资源分配的最小单位,线程是CPU调度的最小单位。每一个进程中至少有一个线程
# 线程开销更小,更轻量级
3 开启线程的两种方式
# 第一种
# from threading import Thread
# import time
# def task():
# print('开始')
# time.sleep(1)
# print('结束')
#
#
# if __name__ == '__main__':
# t=Thread(target=task,) # 实例化得到一个对象
# t.start() # 对象.start()启动线程
# print('主')
# 第二种,通过类继承的方式
# from threading import Thread
# import time
#
# class MyThread(Thread):
# def run(self):
# print('开始')
# time.sleep(1)
# print('结束')
#
# if __name__ == '__main__':
# t=MyThread()
# t.start()
# print('主')
4 TCP服务端实现并发效果
5 线程对象join方法
# 1 等待子线程执行结束
from threading import Thread
import time
def task(n):
print('开始')
time.sleep(n)
print('结束')
if __name__ == '__main__':
t=Thread(target=task,args=(2,))
t.start()
t1=Thread(target=task,args=(3,))
t1.start()
t.join() # 等待子进程执行结束
t1.join()
print('主')
6 同一个进程下的多个线程数据共享
from threading import Thread
import time
money = 99
def task(n):
global money
money=n
print('开始')
# time.sleep(n)
print('结束')
if __name__ == '__main__':
t = Thread(target=task, args=(2,))
t.start()
t1 = Thread(target=task, args=(66,))
t1.start()
t.join()
t1.join()
print(money)
print('主')
7 线程对象及其他方法
# from threading import Thread, current_thread,active_count
# import time
#
#
# def task():
# print('开始')
# print(current_thread().name) # 线程名字
# time.sleep(1)
# print('结束')
#
#
#
# if __name__ == '__main__':
# t1 = Thread(target=task,name='egon')
# t2 = Thread(target=task)
# t1.start()
# t2.start()
# print(active_count()) # 打印出3 ,开了两个线程,还有一个主线程
from threading import Thread, current_thread,active_count
import time
import os
def task(n):
print('开始')
print(current_thread().name) # 线程名字
# 如果打印进程id号,会是什么
print(os.getpid())
time.sleep(n)
print('结束')
if __name__ == '__main__':
t1 = Thread(target=task,name='egon',args=(2,))
t2 = Thread(target=task,args=(8,))
t1.start()
t2.start()
t1.join()
print('---------',t1.is_alive())
print('---------',t2.is_alive())
# 当作线程id号
print('*********',t1.ident)
print('*********',t2.ident)
print(os.getpid())
print(active_count()) # 打印出3 ,开了两个线程,还有一个主线程
# 必须知道的
'''
1 线程t.name t.getName()
2 当前进程下有几个线程存活active_count
3 t1.is_alive() 当前线程是否存活
4 t1.ident 当作是线程id号
'''
### 守护线程
from threading import Thread, current_thread,active_count
import time
import os
def task(n):
print('开始')
time.sleep(n)
# print('-----',active_count())
print('结束')
if __name__ == '__main__':
t1 = Thread(target=task,name='egon',args=(10,))
# t1.daemon = True
t1.setDaemon(True)
t1.start()
t2 = Thread(target=task,name='egon',args=(4,))
t2.start()
print('主')
8 线程互斥锁
from threading import Thread,Lock
import time
import random
money = 99
def task(n,mutex):
global money
# 在修改数据的时候,枷锁
mutex.acquire()
temp = money
time.sleep(0.1)
money = temp - 1
# 修改完以后,释放锁,其它线程就能再次抢到锁
mutex.release()
if __name__ == '__main__':
ll=[]
mutex=Lock()
for i in range(10):
t = Thread(target=task, args=(i,mutex))
t.start()
ll.append(t)
for i in ll:
i.join()
print(money)
9 GIL全局解释器锁理论
#1 python的解释器有很多,cpython,jpython,pypy(python写的解释器)
#2 python的库多,库都是基于cpython写起来的,其他解释器没有那么多的库
#3 cpython中有一个全局大锁,每条线程要执行,必须获取到这个锁
#4 为什么会有这个锁呢?python的垃圾回收机制
#5 python的多线程其实就是单线程
#6 某个线程想要执行,必须先拿到GIL,我们可以把GIL看作是“通行证”,并且在一个python进程中,GIL只有一个。拿不到通行证的线程,就不允许进入CPU执行
# 7 总结:cpython解释器中有一个全局锁(GIL),线程必须获取到GIL才能执行,我们开的多线程,不管有几个cpu,同一时刻,只有一个线程在执行(python的多线程,不能利用多核优势)
# 8 如果是io密集型操作:开多线程
# 9如果是计算密集型:开多进程
以上两句话,只针对与cpython解释器
作业
1 使用多线程和多进程TCP服务端实现并发效果