在了解进程和线程之前来看看,我们所编写的程序。
普通程序
当我们运行它:
进程理解
它再任务管理器中就呈现出一个进程状态,它现在就是一个进程
我们所编写的程序在运行之后呢就像一台电脑开机之后可以处理很多任务,桌面上可以运行很多程序。那么这些运行的程序其实就是一个个进程,一个程序本身其实是一些指令的有序集合,本身呢是没有任何运行的意义,是静态的,进程呢就是程序运行了之后的状态,当我们运行程序的时候,操作系统将程序装载到内存中,操作系统为它分配资源,然后才能运 行。运行起来的应用程序就称之为进程
最直接就是打开任务管理器:
就是程序运行之后的状态====>进程
进程是可并发执行的程序在某个数据集合上的一次计算活动,也是操作系统进行资源分配和调度的基本单位。
进程与程序的区别
-
程序是指令的有序集合,其本身没有任何运行的含义,是一个静态的概念。而进程是程序在处理机上的一次执行过程,它是一个动态的概念。
-
程序可以作为一种软件资料长期存在,而进程是有一定生命期的。程序是永久的,进程是暂时的。
-
进程和程序组成不同:进程是由程序、数据和进程控制块三部分组成的。
-
进程与程序的对应关系:通过多次执行,一个程序可对应多个进程;通过调用关系,一个进程可包括多个程序。
创建一些简单程序来看看多进程:
进程的特征
-
动态性:进程是程序的执行,同时进程有生命周期。
-
并发性:多个进程可同存于内存中,能在一段时间内同时执行。
-
独立性:资源分配和调度的基本单位。
-
制约性:并发进程间存在制约关系,造成程序执行速度不可预测性,必须对进程的并发执行次序、相对执行速度加以协调。
-
结构特征:进程由程序块 、数据块、进程控制块三部分组成。
import os
import time
import multiprocessing
def sing():
for i in range(3):
print('进程1',os.getpid())
print('正在唱歌')
time.sleep(1)
def dance():
for i in range(3):
print('进程2',os.getpid())
print('正在跳舞')
time.sleep(1)
def main():
p1 = multiprocessing.Process(target = sing) #创建进程1
p2 = multiprocessing.Process(target=dance) #创建进程2
start = time.time()
p1.start()
p2.start()
end = time.time()
t = end - start
print(t)
if __name__ == '__main__':
main()
运行结果
0.02094411849975586
第1秒
进程2 6808
正在跳舞
第1秒
进程1 8344
正在唱歌
第2秒
进程2 6808
正在跳舞
第2秒
进程1 8344
正在唱歌
第3秒
进程1 8344
正在唱歌
第3秒
进程2 6808
正在跳舞
运行之后,在任务管理器是有三个python进程的:
程序的理解
主进程从main()开始执行,执行main函数体,当执行到p1.start()时,创建一个子进程,p1 子进程中的代码和主进程相同,只是程序执行的开始是 sing函数体。 主进程执行到p2.start()时,同样复制一份主进程代码从danc函数体开始执行。
了解一下为什么上面程序的start()不是直接运行呢
进程的基本状态
(1)就绪(Ready)状态
当进程已分配到除CPU以外的所有必要的资源,只要获得处理机便可立即执行,这时的进程 状态称为就绪状态。
(2)执行/运行(Running)状态当进程已获得处理机,其程序正在处理机上执行,此时的 进程状态称为执行状态。
(3)阻塞(Blocked)状态正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处 理机而处于阻塞状态。引起进程阻塞的事件可有多种,例如,等待I/O完成、申请缓冲区不 能满足、等待信件(信号)等。
进程挂起状态
由于系统不断创建进程,系统资源特别是主存已不能满足进程运行要求,此时必须将某些进程挂起(suspend),置于磁盘对换区,释放其所占资源,暂时不启用低级调度,起到平滑负载的目的。
进程通讯
刚才我们说了进程可以理解为复制了一份程序有加载到了内存了,进程之间是独立的,如果 我想两个进程之间进行通讯怎么办呢?我们可以使用Queue 队列,队列是一种先进先出的存 储数据结构,之前学到队列理解就是类似与排队,特点是先进先出。 两个进程通讯,就是一个子进程往queue中写内容,另一个进程从queue中取出数据。就实现 了进程间的通讯了。
queue队列
- 创建 queue队列对象 q = multiprocessing.Queue(3) # 3表示只能存放3个数据 参数 :maxsize是队列中允许的最大项数。如果省略此参数,则无大小限制。 返回值q 是队列对象
- put()方法 ,向队列中存放数据。如果队列已满,此方法将阻塞至有空间可用为止。
- get()返回q中的一个项目。如果q为空,此方法将阻塞,直到队列中有项目可用为止。
- get_nowait(): 不等待,直接抛出异常
- full()如果q已满,返回为True
- q.empty() 如果调用此方法时 q为空,返回True。
import multiprocessing
q = multiprocessing.Queue(3)
# 参数maxsize是队列中最大项数,如果忽略此参数,则无大小限制
q.put('hello')
q.put(123)
q.put([1,2,3])
print('队列多少数据',q.qsize())
print('队列是否放满了',q.full())
print('队列数据是否为空',q.empty())
print(q.get())
print(q.get())
print(q.get())
print('队列是否放满了',q.full())
print('队列多少数据',q.qsize())
print('队列数据是否为空',q.empty())
#运行结果
'''
队列多少数据 3
队列是否放满了 True
队列数据是否为空 False
hello
123
[1, 2, 3]
队列是否放满了 False
队列多少数据 0
队列数据是否为空 True
'''
实现多任务的下载
import multiprocessing
def download(q):
data = ['java','python','c++']
#下载到Queue
for i in data:
q.put(i)
print('下载数据')
def processoing_data(q):
for i in range(q.qsize()):
print(q.get())
def main():
#创建队列
q = multiprocessing.Queue()
# 下载数据
p1 = multiprocessing.Process(target=download,args=(q,))
# 处理数据
p2 = multiprocessing.Process(target=processoing_data,args=(q,))
p1.start()
p2.start()
if __name__ == '__main__':
main()
多次运行结果:
它是不一样的。