进程介绍
- 进程:通俗理解一个运行的程序或者软件,进程是操作系统资源分配的基本单位。
- 线程:是程序最小的执行单位。
- 注意:一个程序至少有一个进程,一个进程至少有一个线程,多进程可以完成多任务.
进程的状态
工作中,任务数往往大于cpu的核数,即一定有一些任务正在执行,而另外一些任务在等待cpu进行执行,因此导致了有了不同的状态。
就绪态:运行的条件都已经慢去,正在等在cpu执行
执行态:cpu正在执行其功能
等待态:等待某些条件满足,例如一个程序sleep了,此时就处于等待态
多进程完成多任务
- 导入进程模块
#导入线程模块
import multiprocessing
- Process进程类的语法结构如下:
- Process([group [, target [, name [, args [, kwargs]]]]])
group:指定进程组,目前只能使用None
target:执行的目标任务名
name:进程名字
args:以元组方式给执行任务传参
kwargs:以字典方式给执行任务传参- Process创建的实例对象的常用方法:
start():启动子进程实例(创建子进程)
join([timeout]):是否等待子进程执行结束,或等待多少秒
terminate():不管任务是否完成,立即终止子进- Process创建的实例对象的常用属性:
name:当前进程的别名,默认为Process-N,N为从1开始递增的整数
pid:当前进程的pid(进程号)
进程注意点
- 进程之间不共享全局变量(注意:创建子进程其实是对主进程进行拷贝,进程之间相互独立,访问的全局变量不是同一个,所以进程之间不共享全局变量)
一个进程中地址是唯一的,不同的进程可以有相同的地址
程序唯一确定的一个地址中根据进程的编号+进程内的地址
- 主进程会等待所有子进程执行完成程序再退出
进程,线程对比:
- 1、功能对比
- 进程,能够完成多任务,比如 在一台电脑上能够同时运行多个QQ
- 线程,能够完成多任务,比如 一个QQ中的多个聊天窗口
- 2、定义对比
- 进程是系统进行资源分配基本单位,每启动一个进程操作系统都需要为其分配运行资源。
- 线程是运行程序中的一个执行分支,是CPU调度基本单位。
- 总结:进程是操作系统资源分配的基本单位,线程是CPU调度的基本单位
- 3、关系对比
- 线程是依附在进程里面的,没有进程就没有线程
- 一个进程默认提供一条线程,进程可以创建多个线程
- 4、区别
- 进程之间不共享全局变量
- 线程之间共享全局变量,但是要注意资源竞争的问题,解决办法: 互斥锁或者线程同步
- 创建进程的资源开销要比创建线程的资源开销要大
- 进程是操作系统资源分配的基本单位,线程是CPU调度的基本单位
- 线程不能够独立执行,必须依存在进程中
- 多进程开发比单进程多线程开发稳定性要强
- 5、优缺点
- 多进程:
优点:可以用多核
缺点:资源开销大多 - 线程:
优点:资源开销小
缺点:不能使用多核
代码实例
一边唱歌一边传参进程版传参
# 一边唱歌一边跳舞
import threading
import multiprocessing # 多进程模块
import time
def dance(name):
# 打印
print("dance:", multiprocessing.current_process().name)
print("dance:", threading.current_thread().name)
while True:
print("跳舞", name)
time.sleep(1)
def test():
while True:
print("子进程开线程")
time.sleep(1)
def song(name):
# 开一个线程
threading.Thread(target=test).start()
# 打印
print("song:", multiprocessing.current_process().name)
print("song:", threading.current_thread().name)
while True:
print("唱歌", name)
time.sleep(1)
def main():
"""一边唱歌一边跳舞"""
# # 开启线程
# threading.Thread(target=dance,args=("小班",)).start()
# threading.Thread(target=song,kwargs={"name":"小班"}).start()
# 开启进程
multiprocessing.Process(target=dance, args=("小班",)).start()
multiprocessing.Process(target=song, kwargs={"name": "小班"}).start()
# 打印
print("main:", multiprocessing.current_process().name)
print("main:", threading.current_thread().name)
if __name__ == '__main__':
main()
运行结果
main: MainThread
dance: Process-1
dance: MainThread
跳舞 小班
子进程开线程
song: Process-2
song: MainThread
唱歌 小班
跳舞 小班
子进程开线程
唱歌 小班
队列的使用
# 队列的作用:让进程之间进行通讯
# 使用的队列,创建,放数据,取数据
# 队列中的数据,如果取了,那么这个数据就没有了
# 队列先进先出
import multiprocessing
# 创建队列
queue = multiprocessing.Queue(3) # 队列中最多放三个,如果不写,那么内存大小
# 放入数据
queue.put("123")
queue.put("abc")
queue.put("abc")
# queue.put("abc") # 堵塞了,如果数据超过队列的最大值,会等待
# 取数据
print(queue.get())
print(queue.get())
print("个数:", queue.qsize())
print(queue.get())
# print(queue.get()) # 堵塞了,如果队列的数据为空了,那么会等待
print("取完了")
使用队列实现进程间数据共享
# 使用队列进行进程间的数据共享
# 定义一个队列
import multiprocessing
import time
# 定义一个队列
queue = multiprocessing.Queue(3)
# 一个读一个写
# 写
def write():
for temp in range(100):
queue.put(temp)
time.sleep(1)
# 读
def read():
for temp in range(100):
print("读:", queue.get())
time.sleep(1)
def main():
"""进程之间数据共享使用队列"""
# 使用进程去创建任务
multiprocessing.Process(target=write).start()
multiprocessing.Process(target=read).start()
if __name__ == '__main__':
main()
进程池
同步进程池(任务一个执行完再执行下一个)
# 进程池的作用是用来复用进程
# 复制文件
import os
import time
# 复制
import multiprocessing
def copy():
print("复制开始", os.getpid())
time.sleep(1)
print("复制结束", os.getpid())
def main():
"""用进程池使用"""
# 创建进程池`在这里插入代码片`
pool = multiprocessing.Pool(3) # 会创建3个进程
# 循环复制文件
for temp in range(5):
# 把任务加入到进程池中
pool.apply(copy) # 同步进程池
if __name__ == '__main__':
main()
异步进程池(任务同时去执行)
# 进程池的作用是用来复用进程
# 复制文件
import os
import time
# 复制
import multiprocessing
def copy():
print("复制开始", os.getpid())
time.sleep(4)
print("复制结束", os.getpid())
def main():
"""用进程池使用"""
# 创建进程池同步,一个任务结束,下一个开始
pool = multiprocessing.Pool(3) # 会创建3个进程
# 循环复制文件
for temp in range(5):
# 把任务加入到进程池中
pool.apply_async(copy) # 异步进程池
# 让他等待
pool.close() # 进程池不在添加新的任务了
pool.join() # 让主进程等待进程池的操作结束以后再运行下面的代码
print("主进程结束")
if __name__ == '__main__':
main()
使用进程复制一个简单的文件夹
# 复制文件夹
# 1.创建一个新的文件
# 2. 遍历以前要复制文件夹中的内容
# 3. 循环去复制文件
# 4. 复制:打开文件,读取文件,写入到新文件
import os
import shutil
import multiprocessing
def copy_file(copy_file_before, copy_file_after):
"""复制"""
# 4. 复制:打开文件,读取文件,写入到新文件
# 打开
with open(copy_file_before, 'rb') as f:
content = f.read()
# 写入
with open(copy_file_after, 'wb') as f:
f.write(content)
def main():
"""文件夹复制"""
# 1.创建一个新的文件
# 判断当前的文件夹是否存在,如果存在,那么删除
if os.path.exists('./works_back'):
# 说明存在,删除 文件夹,一定要注意 这个文件夹有可能是非空的
shutil.rmtree("./works_back") # 删除 非空的文件夹
# 创建文件夹
os.mkdir("./works_back")
# 2. 遍历以前要复制文件夹中的内容
files = os.listdir("./works")
print(files)
# 3. 循环去复制文件
for temp in files:
# 复制文件
# copy_file(要复制文件的路径,要保存文件的路径)
# 要复制文件的路径
copy_file_before = "./works/%s" % temp
# 要保存文件的路径
copy_file_after = "./works_back/%s" % temp
# 复制
# copy_file(copy_file_before, copy_file_after)
multiprocessing.Process(target=copy_file, args=(copy_file_before, copy_file_after)).start()
if __name__ == '__main__':
main()
协程版本
# gevent这个是我们的解释器切换
# 复制文件夹
# 复制文件夹
# 1.创建一个新的文件
# 2. 遍历以前要复制文件夹中的内容
# 3. 循环去复制文件
# 4. 复制:打开文件,读取文件,写入到新文件
# 协程使用
# 1. 导入模块
# 2. 打补丁
# 3. 加入任务列表
# 4. 等待
import os
import shutil
import multiprocessing
# 导入模块
import gevent
from gevent import monkey
# 打补丁
monkey.patch_all()
def copy_file(copy_file_before, copy_file_after):
"""复制"""
# 4. 复制:打开文件,读取文件,写入到新文件
# 打开
with open(copy_file_before, 'rb') as f:
content = f.read()
# 写入
with open(copy_file_after, 'wb') as f:
f.write(content)
def main():
"""文件夹复制"""
# 1.创建一个新的文件
# 判断当前的文件夹是否存在,如果存在,那么删除
if os.path.exists('./works_back'):
# 说明存在,删除 文件夹,一定要注意 这个文件夹有可能是非空的
shutil.rmtree("./works_back") # 删除 非空的文件夹
# 创建文件夹
os.mkdir("./works_back")
# 2. 遍历以前要复制文件夹中的内容
files = os.listdir("./works")
print(files)
# 创建一个gevent等待的列表
gevent_list = list()
# 3. 循环去复制文件
for temp in files:
# 复制文件
# copy_file(要复制文件的路径,要保存文件的路径)
# 要复制文件的路径
copy_file_before = "./works/%s" % temp
# 要保存文件的路径
copy_file_after = "./works_back/%s" % temp
# 复制
# copy_file(copy_file_before, copy_file_after)
# 加入任务
gevent_list.append(gevent.spawn(copy_file, copy_file_before, copy_file_after))
# 让我们的协程等待
gevent.joinall(gevent_list)
if __name__ == '__main__':
main()