目录
一、操作系统
操作系统的定义:操作系统是一个用来协调、管理和控制计算机硬件和软件资源的系统程序,它位于硬件和应用程序之间。起承上启下的作用。我们写好的程序只需要给操作系统即可,操作系统会给我们的程序分配内存等等一些操作。
二、多任务
多任务就是同一时刻多个任务同时执行,例如开演唱会时明星一边唱歌一边跳舞,开车时眼睛看路手操作方向盘。这些都是多任务场景。对于电脑来说多任务就是同时运行多个应用程序,例如qq、微信、浏览器等等同时在电脑上运行。
1、电脑实现多任务的原理
例如qq、微信、网易云音乐播放器3个应用程序能同时运行是因为CPU在多个应用程序之间高速切换的结果,当CPU切换到了qq,就用0.01s时间(时间不确定)执行qq程序,然后再随机切换到其他应用程序在执行一段时间,CPU在多个程序之间快速往复执行,我们的肉眼根本感觉不到卡顿,导致我们的错觉感觉是同时运行的效果。如果电脑运行了多个程序有时候会出现卡顿现象是因为cup切换不过来了。
2、单核、双核CPU介绍:
单核CPU 指的是CPU中有一个核心(形象理解CPU是人的头,核心是头里面包含的大脑),用来处理程序。
双核/四核CPU 就是CPU中有2个或者4个核心,(1个脑袋中长了2个大脑或者4个大脑),相当于有2个单核CPU或者是4个单核CPU
3、查看CPU:
电脑-->属性-->设备管理器-->处理器,有4个表示一个CPU中有4个核心。
2.30GHz 表示运算速度,越高越好。例如1s中可以计算多少次。
4、pyth实现多任务的方式
在python中实现多任务有3种方式,进程、线程、协程。
三、进程
1、什么是进程
运行起来的应用程序就称之为进程。也就是说当程序不运行的时候我们称之为程序,当程序运行起来他就是一个进程。通俗的理解就是不运行的时候是程序,运行起来就是进程。程序和进程的对应关系是:程序只有一个,但是进程可以有多个。
2、创建多进程
练习:使用多进程实现控制台先打印唱歌然后在打印跳舞
import time
# 导入multiprocssing模块
import multiprocessing
def sing():
for i in range(3):
print('正在唱歌', i)
time.sleep(1)
def dance():
for i in range(3):
print('正在跳舞...', i)
time.sleep(1)
def main():
# 创建进程
# target指向执行的目标
p1 = multiprocessing.Process(target=sing)
p2 = multiprocessing.Process(target=dance)
# 开启进程
p1.start()
p2.start()
if __name__ == '__main__':
main()
print('程序结束啦')
# 当所有子进程执行完后,主进程才会结束
运行结果:
程序结束啦
正在唱歌 0
正在跳舞... 0
正在唱歌 1
正在跳舞... 1
正在唱歌 2
正在跳舞... 2
程序理解:
主进程从main()开始执行,执行main函数体,当执行到p1.start()时,创建一个子进程,p1子进程中的代码和主进程相同,只是程序执行的开始是 sing函数体。
主进程执行到p2.start()时,同样复制一份主进程代码从danc函数体开始执行。
3、进程的状态
在程序运行的过程中,由于被操作系统的调度算法控制,程序会进入几个状态:就绪,运行和阻塞。
(1)就绪(Ready)状态
当进程已分配到除CPU以外的所有必要的资源,只要获得处理机便可立即执行,这时的进程状态称为就绪状态。
(2)执行/运行(Running)状态当进程已获得处理机,其程序正在处理机上执行,此时的进程状态称为执行状态。
(3)阻塞(Blocked)状态正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态。引起进程阻塞的事件可有多种,例如,等待I/O完成、申请缓冲区不能满足、等待信件(信号)等。
4、进程之间通讯
进程之间是独立的,如果我想两个进程之间进行通讯怎么办呢?我们可以使用Queue 队列,队列是一种先进先出的存储数据结构,就比如排队上厕所一个道理。
两个进程通讯,就是一个子进程往queue中写内容,另一个进程从queue中取出数据。就实现了进程间的通讯了。
1、queue队列
(1).创建 queue队列对象
q = multiprocessing.Queue(3) # 3表示只能存放3个数据
参数 :maxsize是队列中允许的最大项数。如果省略此参数,则无大小限制。
返回值q 是队列对象
(2.)put()方法 ,向队列中存放数据。如果队列已满,此方法将阻塞至有空间可用为止。
(3).get()返回q中的一个项目。如果q为空,此方法将阻塞,直到队列中有项目可用为止。
(4).get_nowait(): 不等待,直接抛出异常
(5).full()如果q已满,返回为True
(6).q.empty() 如果调用此方法时 q为空,返回True。
# 导入多进程模块
import multiprocessing
# 可以写参数,不写参数表示可以放任意多个数据
# 指定参数后,只能存放指定的个数数据
q = multiprocessing.Queue(3)
q.put('哈哈')
q.put(123)
q.put([1, 2, 3])
# q.put('lala') # 阻塞了,直到有数据被使用后,才能继续放进去,否则一直等待放入
# q.put_nowait('ahahah') # 不等待,直接抛异常
# ret=q.get()
# print(ret)
print(q.get()) # 一个个取出来 # 哈哈
print(q.get()) # 123
print(q.get()) # [1,2,3]
# q.get() # 如果队列中没有了数据,则一直等待,直到有数据才执行
# q.get_nowait() # 如果队列中没有了数据,则不等待直接抛出异常 # queue.Empty
print(q.empty()) # 判断队列中是否还有数据,如果没有返回True # True
print(q.full()) # 判断队列是否满了,如果满了返回True # False
print(q.qsize()) # 0 # 测量队列的长度 队列里面元素取出来之后就变成了0
2、进程之间的通信
练习:实现两个进程之间简单的传输下载功能
from multiprocessing import Process, Queue
def download_data(q):
lst = ['a', 'b', 'c']
for i in lst:
q.put(i) # 将下载的数据保存到队列中
print('下载完了数据')
def process_data(q):
for i in range(q.qsize()):
print(q.get())
# 下载完了数据
print('接受完数据啦')
def main():
# 1.先创建一个队列
q = Queue()
# 2.创建两个子进程 data date
q1 = Process(target=download_data, args=(q,))
q2 = Process(target=process_data, args=(q,))
q1.start()
q2.start()
if __name__ == '__main__':
main()
print('程序结束了...')
运行结果:
程序结束了...
下载完了数据
a
b
c
接受完数据啦
5、进程池
当需要创建的子进程数量不多时,我们可以直接利用multiporcessing中的Process动态生成多个进程,但是如果现在有100个任务需要处理,那我们需要多少个子进程呢,这时候就需要创建一个进程池,创建进程池对象的时候可以指定一个最大进程数,当有新的请求提交到进程池中,如果池中的进程数还没有满,那么就会创建一个新的进程用来执行该请求,但是如果池中的进程数满了,该请求就会等待,知道进程池中的进程有结束的了,才会使用这个结束的进程来执行新的任务。
join 主进程等待所有子进程执行完毕,必须在close之后。
close 等待所有进程结束才关闭线程池
练习:创建一个简单的进程池
from multiprocessing import Process, Pool
import time
def foo(i):
print("i的值是:", i)
time.sleep(1)
print('end...')
if __name__ == '__main__':
pool = Pool(3) # 创建进程池对象
for i in range(5):
pool.apply_async(func=foo,args=(i,)) # 将任务添加到进程池中
pool.close() # 关闭进程池,等待所有程序执行完后
pool.join() # 主进程等待所有子进程执行完毕之后主进程才往下执行,必须在close后面
print('程序结束了...')
运行结果;
i的值是: 0
i的值是: 1
i的值是: 2
end...
i的值是: 3
end...
i的值是: 4
end...
end...
end...
程序结束了...