知识点补充:
1、操作系统的调度算法:
时间片轮转法
多级反馈队列
2、同步异步(任务的提交方式):
同步:提交任务之后原地等待任务的返回结果,才能进行下一步操作
异步:提交任务之后不等待任务的返回结果,直接进行下一步操作
3、阻塞非阻塞
阻塞:程序处于阻塞态
非阻塞:程序处于运行或就绪态
4、进程理论:
进程:正在运行的程序
多道技术:
空间上的复用
多个程序共用一套硬件设备
时间上的复用
CPU来回切换:切换+保存状态
1、程序占用cpu时间过长会被操作系统强行剥夺走cpu的执行权限
2、程序的IO操作指的是:
input 网络请求(recv accept) time.sleep 文件读写 print
5、创建进程的本质:在内存中申请一块独立的内存空间,需要申请内存空间,还需要拷贝代码
#1、进程间通信
#队列:先进先出
#堆栈:先进后出
#利用队列实现进程间通信
from multiprocessing import Queue
q = Queue(5) #里面的参数代表最多放5个数据
q.put(1) #往队列里放数据
q.put(1)
q.put(1)
q.put(1)
print(q.full()) #判断队列是否放满了,此时显示False,还有一个位置没放数据
q.put_nowait(2) #往队列里放数据,
# q.put_nowait(2) #当超过队列里允许放置数据个数的最大值以后,系统会报错
# q.put(1) #当超过最大值,此时不会报错,只是程序会卡住,不会继续运行
q.get() #从队列里取数据
q.get()
q.get()
print(q.empty()) #当前的队列里面是否还存在数据,此时显示False
q.get()
q.get_nowait() #从队列里取值,因为还存在数据,所以正常取值
# q.get_nowait() #因为队列里面的值全部取完了,所以这次系统会报错
# q.get() #队列为空,get会在原地等待队列中放置数据
print(q.empty()) #此时显示True,队列里面所存的数据全部被取出
#2、基于队列实现进程间通信
from multiprocessing import Queue,Process
def producer(q):
q.put('我是造数据的')
def consumer(q):
print(q.get())
if __name__ == '__main__':
q = Queue()
p1 = Process(target=producer,args=(q,))
p2 = Process(target=consumer,args=(q,))
p1.start()
p2.start()
#3、生产者消费者模型
生产者:生成数据
消费者:处理数据
解决供需不平衡的问题:
定义一个队列,用来存放固定数量的数据
解决生产者和消费者不需直接打交道,双方通过队列实现数据传输的问题
Queen,JoinableQueue :管道+锁,后者稍微高级一些
from multiprocessing import JoinableQueue,Process
import random,time
def producer(name,food,q):
for i in range(5):
data = '%s拉出了%s,%s'%(name,food,i)
time.sleep(random.randint(1,3))
print(data)
q.put(data) #将数据放入队列中
def consumer(name,q):
while True:
data = q.get()
time.sleep(random.randint(1,3))
print('%s消化了%s'%(name,data))
q.task_done() #告诉队列,已经将数据取出并消化完毕
if __name__ == '__main__':
q = JoinableQueue() #生产一个队列对象
a1 = Process(target=producer,args=('tank','披萨',q))
a2 = Process(target=producer,args=('egon','面包',q))
b1 = Process(target=consumer,args=('owen',q))
b2 = Process(target=consumer,args=('fuck',q))
a1.start()
a2.start()
b1.daemon = True
b2.daemon = True
b1.start()
b2.start()
#等待生产者生产完所有的数据
a1.join()
a2.join()
#等待队列里的数据全部取出
q.join()
print('主进程')
#可能是因为3.7版本的问题,导致终端输出的时候,多行数据再同一行打印,剩下一些空行???
#4、线程
1、什么是线程
进程:资源单位
线程:执行单位
二者的联系:每一个进程中会自带一个进程
2、线程存在的必要性
开启一个进程:
申请内存空间 耗时
将代码拷贝到申请的内存空间中 耗时
开启线程:
不需要申请内存空间
因此,开启线程的开销远远小于开进程!
5、开启线程的方式
#方式一: 通过函数
from threading import Thread
import time
def task(name):
print('%s is running'%name)
time.sleep(1)
print('%s is over'%name)
if __name__ == '__main__': #因为线程不需要加载模块,所以这一步操作可有可无
t = Thread(target=task,args=('michael',))
t.start() #开启线程的速度非常快,几乎代码执行完线程就已经开启
# time.sleep(0.5)
print('主线程')
#方式二: 类的继承
from threading import Thread
import time
class MyThread(Thread):
def __init__(self,name):
#涉及到父类方法的重写,最好先调用super()
super().__init__()
self.name = name
def run(self):
print('%s is running'%self.name)
time.sleep(1)
print('%s is over'%self.name)
t = MyThread('michael')
t.start()
print('主线程')
#6、线程之间数据共享
from threading import Thread
import os
x = 100
def task():
global x
x=99
print('子线程所对应的进程的pid',os.getpid()) #7280
t = Thread(target=task)
t.start()
t.join() #存在有无,都没有影响
print(x) #99
print('主线程所对应进程的pid',os.getpid()) #7280
#上述的操作可以说明这几点:
# 1、线程之间共享的是进程的数据
# 2、线程本身是不存在pid的,存在的是上一级进程的pid
#7、线程互斥锁
from threading import Thread,Lock
import time
import random
#下面为没有加锁的,导致所有线程拿到的数据是同一份,没有达到预期的效果
n = 10
def task():
global n
tmp = n
time.sleep(0.1) #存在延迟,导致所有线程拿到的n都是10,处理以后所有的返回值都是9
#若不存在延迟,最后的结果为n=0, 所有的线程都处理了数据,具体过程日后再谈 ????
n = tmp - 1
t_list = []
for i in range(10):
t = Thread(target=task)
t.start()
t_list.append(t)
for t in t_list:
t.join() #让主线程等待10个子线程结束以后再运行自身
print(n) #n = 9
#加锁
mutex = Lock()
n = 10
def task():
global n
mutex.acquire() #加锁 让线程从并行改变为了串行
tmp = n
time.sleep(0.1)
n = tmp - 1
mutex.release() #释放锁 一个线程结束以后,其他的线程开始了竞争
t_list = []
for i in range(10):
t = Thread(target=task)
t.start()
t_list.append(t)
for t in t_list:
t.join()
print(n) #n=0
#8、线程的其他属性与方法
from threading import Thread,active_count,current_thread
def task(name):
print('%s is running'%name)
time.sleep(1)
print('%s is over'%name)
t1 = Thread(target=task,args=('michael',))
t2 = Thread(target=task,args=('michael',))
t1.start()
t2.start()
print(active_count()) #当前存活的线程数,加上主线程 3
print(current_thread()) #产生了一个对象
t1.join()
t2.join()
print(active_count()) #回收了两个子线程,还剩下一个主线程 1
#9、守护进程
from threading import Thread,active_count
import time
def task(name):
print('%s is running'%naem)
time.sleep(0.1)
print('%s is over'%name)
t = Thread(target=task,args=('michael',))
t.daemon = True #主线程结束,守护线程也会立刻结束,然而在这场景,没什么具体的用处
t.start()
print(active_count()) #没有延迟时,理论上为1
print('主')
print(active_count()) #没有延迟时,理论上为1 可能是受限于计算机硬件的能力,软件比硬件发展快好多