一、知识储备
并发编程中的重要概念
串行:自上而下,顺序执行
并发:在多个进程间快速的来回切着执行
并行:是真正的同时运行,必须具备多核CPU,有几个核心就能并行几个任务,当任务数量超过核心数还是并发执行
以上三个概念都是用于描述处理任务的方式
阻塞:指的是程序遇到IO操作,无法继续执行代码的一种状态
非阻塞:程序没有遇到IO操作的一个状态
阻塞非阻塞可以用来描述执行任务的方式
input()默认是一个阻塞的操作
我们可以用一些手段将阻塞的操作变成非阻塞的操作,例如非阻塞的socket
一个进程的三种状态
阻塞:
运行:
就绪:
进程与程序
程序是一堆代码放在文件中,通常后缀为exe,原本是存储在硬盘上的。
进程是将代码从硬盘读取到内存然后执行产生的
进程是由程序产生的
一个程序可以产生多个进程,例如QQ多开,每一个进程都具备一个PID,进程编号是唯一的
PID和PPID
PID是当前进程的编号
PPID是父进程的编号
注意:当我们运行py文件时,运行的是python解释器
二、创建进程的两种方式
- 方式一:
from multiprocessing import Process#导入,实例化这个类,执行target
import os
#子进程
def task():
print('process')
print(os.getpid())
if __name__ == '__main__':
# 实例化一个进程对象,并制定他要做的事,用函数来指定
p = Process(target=task,args = (3,)) # 注意这里task不要加括号,不然直接执行了,后后面可以跟参数,只有一个的时候要,
p.start() # 给操作系统发送消息,让它开启进程
print('父进程%s' % os.getpid())
print('over')
- 方式二:
import os
from multiprocessing import Process
class Downloader(Process):
# 当你想对进程高度自定义的时候,可以继承一下类
def __init__(self, url, size, name):
super().__init__()
self.url = url
self.size = size
self.name = name
def run(self):
print(os.getpid())
pass
if __name__ == '__main__':
m = Downloader()
m.start()
print('over', os.getpid())
**三、join函数 **
from multiprocessing import Process
import time
def task1(name):
for i in range(10000):
print("%s run" % name)
def task2(name):
for i in range(100):
print("%s run" % name)
if __name__ == '__main__': # args 是给子进程传递的参数 必须是元组
p1 = Process(target=task1,args=("p1",))
p1.start() # 向操作系统发送指令
# p1.join() # 让主进程 等待子进程执行完毕在继续执行
p2 = Process(target=task2,args=("p2",))
p2.start() # 向操作系统发送指令
p2.join() # 让主进程 等待子进程执行完毕在继续执行
p1.join()
#需要达到的效果是 必须保证两个子进程是并发执行的 并且 over一定是在所有任务执行完毕后执行
print("over")
案例
# join的使用
from multiprocessing import Process
import time
def task1(name):
for i in range(10):
print("%s run" % name)
if __name__ == '__main__': # args 是给子进程传递的参数 必须是元组
ps = []
for i in range(10):
p = Process(target=task1,args=(i,))
p.start()
ps.append(p)
# 挨个join以下
for i in ps:
i.join()
print("over")
四、进程对象的几种属性
from multiprocessing import Process
def task():
print('aa')
if __name__ == '__main__':
P = Process(target=task, name='老司机进程')
print(P.name) # 开了多任务的时候分辨不出来,就可以自定义名字
# P.daemon 守护进程
print(P.exitcode) # 退出码 , 0表示正常退出
# 用途:类似于错误码
print(P.is_alive()) # 查看是否存活
print(P.pid) # 获取进程id
P.terminate() # 终止进程 与strat 相同的是不会立即终止