文章目录
进程的概念
进程即正在执行的一个过程。进程是对正在运行程序的一个抽象。
进程是是系统进行资源分配和调度的基本单位
狭义定义:进程是正在运行的程序的实例
广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。
程序:就是一堆躺在硬盘上的代码,是'死'的
进程:表示程序正在执行的过程,是'h'的
协程:解决单线程下的高并发
# 进程中还可以开线程
线程就是干活的人,进程不是干活的人
线程就是最小的执行单元
进程和线程都是有操作系统来调度的
进程的并行和并发
# 并行:就是在一个精确的时间片刻
# 并发:在一个时间段上可以看出是同时执行的
同步异步阻塞非阻塞
同步与异步
1.同步与异步
同步和异步关注的是消息通信机制 (synchronous communication/ asynchronouscommunication)
所谓同步,就是在发出一个*调用*时,在没有得到结果之前,该*调用*就不返回。但是一旦调用返回,就得到返回值了。
换句话说,就是由*调用者*主动等待这个*调用*的结果。
而异步则是相反,*调用*在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在*调用*发出后,*被调用者*通过状态、通知来通知调用者,或通过回调函数处理这个调用。
典型的异步编程模型比如Node.js
举个通俗的例子:
你打电话问书店老板有没有《分布式系统》这本书,如果是同步通信机制,书店老板会说,你稍等,”我查一下",然后开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果)。
而异步通信机制,书店老板直接告诉你我查一下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。然后查好了,他会主动打电话给你。在这里老板通过“回电”这种方式来回调。
阻塞与非阻塞
2. 阻塞与非阻塞
阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.
阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。
还是上面的例子:
你打电话问书店老板有没有《分布式系统》这本书,你如果是阻塞式调用,你会一直把自己“挂起”,直到得到这本书有没有的结果
如果是非阻塞式调用,你不管老板有没有告诉你,你自己先一边去玩了, 当然你也要偶尔过几分钟check一下老板有没有返回结果。
在这里阻塞与非阻塞与是否同步异步无关。跟老板通过什么方式回答你结果无关。
multiprocess模块
仔细说来,multiprocess不是一个模块而是python中一个操作、管理进程的包。 之所以叫multi是取自multiple的多功能的意思,在这个包中几乎包含了和进程有关的所有子模块。由于提供的子模块非常多,为了方便大家归类记忆,我将这部分大致分为四个部分:创建进程部分,进程同步部分,进程池部分,进程之间数据共享。
multiprocess.process模块
process模块是一个创建进程的模块,借助这个模块,就可以完成进程的创建。
process模块介绍
Process([group [, target [, name [, args [, kwargs]]]]]),由该类实例化得到的对象,表示一个子进程中的任务(尚未启动)
强调:
1. 需要使用关键字的方式来指定参数
2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号
参数介绍
- group参数未使用,值始终为None
- target表示调用对象,即子进程要执行的任务
- args表示调用对象的位置参数元组,`args=(1,2,'egon',)`
- kwargs表示调用对象的字典,`kwargs={'name':'egon','age':18}`
- name为子进程的名称
方法介绍
p.start():启动进程,并调用该子进程中的p.run()
p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法
p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁
p.is_alive():如果p仍然运行,返回True
p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程
属性介绍
p.daemon:默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置
p.name:进程的名称
p.pid:进程的pid
p.exitcode:进程在运行时为None、如果为–N,表示被信号N结束(了解即可)
p.authkey:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络连接的底层进程间通信提供安全性,这类连接只有在具有相同的身份验证键时才能成功(了解即可)
进程的创建
import time
from multiprocessing import Process
def f(name):
print('hello', name)
print('我是子进程')
if __name__ == '__main__':
p = Process(target=f, args=('bob',))
p.start()
time.sleep(1)
print('执行主进程的内容了')
# 一个进程中必须至少有一个线程
# 在wins中,开启进程必须写在__main__里面
# 开启进程必须调用start方法
如何开启进程
from multiprocessing import Process
def write():
with open('aaa', 'w') as f:
f.write('hello')
# write()
# 一个进程中必须至少有一个线程
# 在wins中,开启进程必须写在__main__里面
if __name__ == '__main__':
p = Process(target=write)
# 开启进程必须调用start方法
p.start()
p1 = Process(target=write)
# 开启进程必须调用start方法
p1.start()
Process类的参数
from multiprocessing import Process
def task(age, name):
# with open('aaa', 'w') as f:
# f.write('hello')
print(name)
print(age)
# 在wins中,开启进程必须写在__main__里面
if __name__ == '__main__':
"""
target=None, name=None, args=(), kwargs={},
*, daemon=None
"""
# p = Process(target=write, name='洋哥很帅')
# p = Process(target=task, args=('egon', 18))
p = Process(target=task, kwargs={'name': 'qq', 'age': 11})
# 开启进程必须调用start方法
p.start()
print(p.name) # 进程名:Process-1
Process类的方法
if __name__ == '__main__':
p = Process(target=task, kwargs={'name': 'qq', 'age': 11}) #
# 开启进程必须调用start方法
p.start() # 开启进程 通知操作系统去开启进程
# p.run()
# p.terminate() 杀掉进程
# p.is_alive() 查看进程是否存活
# p.join() 等待子进程执行完毕
# p.terminate()
# print(p.is_alive())
# p.terminate()
# time.sleep(2)
# print(p.is_alive())
p.join()
Process类的属性介绍
if __name__ == '__main__':
p = Process(target=task, kwargs={'name': 'qq', 'age': 11}) #
# 开启进程必须调用start方法
"""
守护进程:父进程执行完毕,子进程也立马结束
"""
# p.daemon = True # 强调:一定要放在start之前
p.start() # 开启进程 通知操作系统去开启进程
print(p.name) # 进程名
print(p.pid) # 进程id
p.daemon = True # 强调:一定要放在start之前, 守护进程
获取进程id号
from multiprocessing import Process
import time
import os
def task(age, name):
print("子进程的id号: %s" % os.getpid())
print("父进程的id号:%s" % os.getppid())
time.sleep(10)
if __name__ == '__main__':
p = Process(target=task, kwargs={'name': 'qq', 'age': 11}) #
p.start()
print(p.pid)
print("main里的主进程的id号:%s" % os.getpid())
print("main里面的父进程的id号:%s" % os.getppid())
time.sleep(10)
print("end=========>")
同时运行多个进程
from multiprocessing import Process
import time
import os
def task(i):
time.sleep(3)
print(i)
if __name__ == '__main__':
ll = []
# for i in range(10):
# p = Process(target=task, args=(i, )) #
# p.start()
# p.join() # 变成串行执行
# for i in range(10):
# p = Process(target=task, args=(i,)) #
# p.start()
# ll.append(p)
#
# for j in ll:
# j.join()
p = Process(target=task, args=(1, ))
p.start()
p.name = 'aaaa'
print(p.pid)