什么是并发编程?
并发就是一起发生.
就是指多个任务同时被执行
什么是进程?
进程指的是正在运行的程序,是一系列过程的统称,也是操作系统在调度和进行资源分配的基本单位
进程是实现并发的一种方式
多进程的实现原理--多道技术
cpu在执行一个任务的过程中,若需要操作硬盘,则发送操作硬盘的指令,指令一旦发出,硬盘上的机械手臂华东读取数据到内存中, 这一段时间,cpu需要等待,对于cpu来说时间很长,如果我们让cpu在这段时间内切换到去做其他任务,这样就能充分利用cpu.这就是多道技术产生的技术背景.
多道技术:
多道技术中的多道指的是多个程序,多道技术的实现是为了解决多个程序竞争或者说共享同一个资源的有序调度问题. 解决方式就是多路复用.
空间上的复用:将内存分为几个部分,每个部分放入一个程序,这样同一时间内存中就有了多道程序
时间上的复用: 当一个程序在等待I/O时,另一个程序可以使用cpu,如果内存中可以同时存放足够多的作业,则cpu的利用率可以接近100%
(操作系统在采用多道技术后,可以控制进程的切换,或者说进程之间去争抢cpu的执行权限.这种切换不仅会在一个进程遇到I/O时进行,也会在一个进程占用cpu时间过长时切换)
空间上的复用: 最大问题是程序之间的内存必须分割,这种分割需要在硬件层面实现,由操作系统控制,如果内存彼此不分割,则一个程序可以访问另一个程序的内存. 丧失的就是安全性(比如qq程序可以访问操作系统的内存,意味着qq可以拿到操作系统的所有权限), 其次丧失的就是稳定性, 某个程序崩溃时有可能把别的程序的内存也给回收了.
进程与程序
进程是正在运行的程序,程序时程序员编写的一堆代码,也就是一堆字符,当这对代码被系统加载到内存中并执行时,就有了进程.
注意: 一个程序可以产生多个进程
PID和PPID
PID:
在一个操作系统中通常都会运行多个应用程序,也就是多个进程,如何来区分进程? 系统会给每一个进程分配一个进程编号即PID,如同人需要身份证号来区分
验证: 在cmd中
tasklist用于查看所有的进程信息
tasklist /f /pid pid该命令可以用于结束指定进程
# 在python中可以使用os模块来获取pid
import os
print(os.getpid())
PPID:
当一个进程a开启了另一个进程b时, a陈伟b的父进程, b为a的子进程
# 在python中可以使用os模块来获取ppid
import os
print("self",os.getpid()) # 当前进程自己的pid
print("parent",os.getppid()) # 当前进程的父进程的pid
并发与并行, 阻塞与非阻塞
并发: 指的是多个事件同时发生
并行: 指的是多个事件都是进行着的(在计算机中单核cpu是无法真正并行的,之所以单核cpu也能同时运行qq和微信其实就是并发执行)
阻塞与非阻塞指的是程序的状态:
阻塞状态是因为程序遇到了IO操作,或者是sleep, 导致后续的代码不能被CPU执行. 非阻塞与之相反,表示程序正在正常被CPU执行
进程的三种状态: 就绪态,
多道技术会在进程执行时间过长或遇到IO时自动切换其他进程,意味着IO操作与进程被剥夺CPU执行权都会造成进程阻塞
python中实现并发
方式一: 实例化Process类
# 实例化Process类
from multiprocessing import Process
import time
def task(name):
print('%s is running' % name)
time.sleep(2)
print('%s is done' % name)
if __name__ == '__main__':
# 在windows系统上,开启子进程的操作一定要放在main下面
# args 是元组类型
p = Process(target=task, args=('kopa',))
p.start()
print('=====')
方式二: 继承Process类,并覆盖run方法
# 继承Process类,并覆盖run方法
from multiprocessing import Process
import time
class MyProcess(Process):
def __init__(self, name):
super().__init__()
self.name = name
def run(self):
print('%s is running' % self.name)
time.sleep(1)
print('%s is done' % self.name)
if __name__ == '__main__':
p = MyProcess('kopa')
p.start()
print('=======')
# =======
# kopa is running
# kopa is done
进程之间相互隔离(独立)
from multiprocessing import Process
import time
a = 1000000000000
def task():
global a
a = 0
print("子进程的", a)
if __name__ == '__main__':
p = Process(target=task)
p.start()
# 给操作系统发送请求后 代码继续往下运行
# 至于子进程 什么时候创建 什么是执行 都跟当前进程没关系
time.sleep(1)
print("自己的", a)
# 子进程的 0
# 自己的 1000000000000
# 子进程中的数据修改 不会影响父进程
join函数
调用start函数后的操作就由操作系统来处理,至于何时开启进程,进程何时执行,何时结束都与应用程序无关,所以当前进程会继续往下执行,join函数就可以是父进程等待子进程结束后继续执行
import time
from multiprocessing import Process
def task():
print("上传文件....")
time.sleep(3)
print("上传结束...")
if __name__ == '__main__':
p = Process(target=task)
p.start()
p.join()
# 本质上是提高了子进程优先级 当CPU在切换时 会优先切子进程
print("上传文件成功!")
# 上传文件....
# 上传结束...
# 上传文件成功!
from multiprocessing import Process
import time
def task(num):
print('hello %s ' % num)
# time.sleep(2)
if __name__ == '__main__':
start_time = time.time()
ps = []
for i in range(5):
p = Process(target=task, args=(i,))
p.start()
# p.join() # 11.483961820602417
ps.append(p)
for p in ps:
p.join() # 2.5066349506378174
print(time.time() - start_time)
print('over')
# hello 0
# hello 1
# hello 2
# hello 3
# hello 4
# 0.5186610221862793
# over
Process常用属性
from multiprocessing import Process
import time
def task():
pass
if __name__ == '__main__':
p = Process(target=task(), name='kopa')
p.start()
print(p.name) # kopa
time.sleep(1)
print(p.is_alive()) # 代码是否执行完(布尔值)
# p.terminate() # 终止进程
print(p.pid) # 进程的id
# p.daemon # 守护进程(当主进程结束,当前也结束)