本文已参与「新人创作礼」活动,一起开启掘金创作之路。
多任务-进程
4.1,进程及状态
-
进程
程序:硬盘上,u盘上面的exe(二进制文件)可执行文件,是死的进程:运行起来的程序叫进程,运行的 进程能够使用资源(键盘,摄像头,网络)
-
进程的状态
工作中,任务往往大于cpu核数,即一定有一些任务正在执行,而另外一些任务在等待cpu进行执行,因此导致了有了不同的状态
- 就绪态:运行的太偶见都已经慢去,正在等待pu执行
- 执行态:cpu正在执行某功能
- 等待态:等待某些条件满足,例如一个程序sleep了,此时就处于等待态
4.2,进程(重点)
-
使用进程来进行多任务
用法与threading线程相类似
查看线程状态(Linux下):
ps -aux杀死某个进程(Linux下):
kill 进程ID# !/usr/bin/env python # _*_ coding:utf-8 _*_ # author:满怀心 2019/8/3 13:40 """ # code is far away from bugs with the god animal protecting I love animals. They taste delicious. ┏┓ ┏┓ ┏┛┻━━━┛┻┓ ┃ ☃ ┃ ┃ ┳┛ ┗┳ ┃ ┃ ┻ ┃ ┗━┓ ┏━┛ ┃ ┗━━━┓ ┃ 神兽保佑 ┣┓ ┃ 永无BUG! ┏┛ ┗┓┓┏━┳┓┏┛ ┃┫┫ ┃┫┫ ┗┻┛ ┗┻┛ """ import time import multiprocessing def text1(): while True: print('1----------') time.sleep(1) return def text2(): while True: print('2----------') time.sleep(1) def main(): t1 = multiprocessing.Process(target=text1) t2 = multiprocessing.Process(target=text2) t1.start() t2.start() if __name__ == '__main__': main()能实现多任务,但是占用资源大
写时拷贝:(如果中途代码发生改变,所有子进程都会改变)
4.3,线程和进程的区别
-
功能
进程: 能完成多任务,比如电脑上开多个QQ,是资源的总称线程: 能完成多任务,比如QQ上开多个聊天窗口,轻量级
注意:
先有进程才有线程,线程是拿着进程的资源去运行的,一个进程里面至少有一个主线程- 线程的划分尺度小于进程(资源比进程少),使得
多线程程序的并发性高 进程是资源分配的单位,线程是资源调度(执行)的单位。在一个进程里,线程之间资源共享,极大的提高了程序的运行速度
多线程:一个进程里面有多个线程执行任务多进程:多个进程里面有一个或多个线程执行任务- 线程不能够独立执行,必须依存在进程中
- 可以将进程理解工厂里的一条流水线,而其中的线程就是这个流水线上的工人
优缺点:线程和进程在使用上各有优缺点:线程执行开销小,但是不利于资源的管理和保护;而进程相反
4.4,进程间的通信
Process之间有时需要通信,操作系统提供了很多机制来实现进程间的通信,降低程序耦合度
-
Queue的使用
可以使用multiprocessing模块的Queue实现多进程之间的数据传递,Queue本身是一个消息队列程序
# !/usr/bin/env python # _*_ coding:utf-8 _*_ # author:满怀心 2019/8/4 15:01 """ # code is far away from bugs with the god animal protecting I love animals. They taste delicious. ┏┓ ┏┓ ┏┛┻━━━┛┻┓ ┃ ☃ ┃ ┃ ┳┛ ┗┳ ┃ ┃ ┻ ┃ ┗━┓ ┏━┛ ┃ ┗━━━┓ ┃ 神兽保佑 ┣┓ ┃ 永无BUG! ┏┛ ┗┓┓┏━┳┓┏┛ ┃┫┫ ┃┫┫ ┗┻┛ ┗┻┛ """ import multiprocessing def download_from_web(q): """下载数据""" data = [1, 2, 3, 4] for i in data: q.put(i) print('数据已经全部添加到队列') def analysis_data(q): """数据处理""" waiting_analysis_data = list() while True: data = q.get() if q.empty(): break print('数据处理完毕') def main(): q = multiprocessing.Queue() t1 = multiprocessing.Process(target=download_from_web, args=(q, )) t2 = multiprocessing.Process(target=analysis_data, args=(q, )) t1.start() t2.start() if __name__ == '__main__': main()
4.5,进程池
能够重复利用进程里面的进程
# !/usr/bin/env python
# _*_ coding:utf-8 _*_
# author:满怀心 2019/8/4 16:41
"""
# code is far away from bugs with the god animal protecting
I love animals. They taste delicious.
┏┓ ┏┓
┏┛┻━━━┛┻┓
┃ ☃ ┃
┃ ┳┛ ┗┳ ┃
┃ ┻ ┃
┗━┓ ┏━┛
┃ ┗━━━┓
┃ 神兽保佑 ┣┓
┃ 永无BUG! ┏┛
┗┓┓┏━┳┓┏┛
┃┫┫ ┃┫┫
┗┻┛ ┗┻┛
"""
from multiprocessing import Pool
import os, time, random
def worker(msg):
t_start = time.time()
print('{} 开始执行,进程号为 : {}'.format(msg, os.getpid()))
time.sleep(random.random()*2)
t_stop = time.sleep()
print('{} 结束执行,耗时{:2f}'.format(msg, (t_stop-t_start)))
po = Pool(3) # 定义一个进程池,最大进程数为3
for i in range(10):
po.apply_async(worker, (i, ))
print('-----start-----')
po.close() # 关闭进程池,关闭后po不在接收新的请求
po.join() # 阻塞进程,等待po中所有的子进程执行完毕,必须放在close语句后,不然主死子死
print('-----stop-----')
运行结果
4.6,文件夹的拷贝器(多进程版本)
文件的复制:用rb读取旧文件,创建新文件,用wb写入
# !/usr/bin/env python
# _*_ coding:utf-8 _*_
# author:满怀心 2019/8/4 21:53
"""
# code is far away from bugs with the god animal protecting
I love animals. They taste delicious.
┏┓ ┏┓
┏┛┻━━━┛┻┓
┃ ☃ ┃
┃ ┳┛ ┗┳ ┃
┃ ┻ ┃
┗━┓ ┏━┛
┃ ┗━━━┓
┃ 神兽保佑 ┣┓
┃ 永无BUG! ┏┛
┗┓┓┏━┳┓┏┛
┃┫┫ ┃┫┫
┗┻┛ ┗┻┛
"""
import os
import multiprocessing
def copy_file(index, file_name, old_folder_name, new_folder_name):
print('-----模拟copy文件, 从{} => {}, 当前文件 {} : {}-----'.format(old_folder_name, new_folder_name, index, file_name))
old_f = open(r'{}/{}'.format(old_folder_name, file_name), 'rb')
content = old_f.read()
old_f.close()
new_f = open(r'{}/{}'.format(new_folder_name, file_name), 'wb')
new_f.write(content)
new_f.close()
def main():
# 1. 获取用户要copy的文件夹的名字
old_folder_name = input('请输入要copy的文件夹名:\t')
# 2. 创建一个新的文件夹
new_folder_name = '[复制]{}'.format(old_folder_name)
try:
os.mkdir(new_folder_name)
except Exception:
pass
# 3. 获取文件夹下所有文件的名字
file_names = os.listdir(old_folder_name)
# print(file_names)
# 4. 创建进程池
po = multiprocessing.Pool(5)
# 5. 向进程池里面添加 copy 文件的任务
for index, file_name in enumerate(file_names):
po.apply_async(copy_file, args=(index, file_name, old_folder_name, new_folder_name))
po.close() # 停止向进程池提交任务
po.join() # 阻塞主进程,等待子进程结束
if __name__ == '__main__':
main()
-添加进度条版
# !/usr/bin/env python
# _*_ coding:utf-8 _*_
# author:满怀心 2019/8/4 21:53
"""
# code is far away from bugs with the god animal protecting
I love animals. They taste delicious.
┏┓ ┏┓
┏┛┻━━━┛┻┓
┃ ☃ ┃
┃ ┳┛ ┗┳ ┃
┃ ┻ ┃
┗━┓ ┏━┛
┃ ┗━━━┓
┃ 神兽保佑 ┣┓
┃ 永无BUG! ┏┛
┗┓┓┏━┳┓┏┛
┃┫┫ ┃┫┫
┗┻┛ ┗┻┛
"""
import os
import multiprocessing
def copy_file(index, file_name, old_folder_name, new_folder_name, q):
# print('-----模拟copy文件, 从{} => {}, 当前文件 {} : {}-----'.format(old_folder_name, new_folder_name, index, file_name))
old_f = open(r'{}/{}'.format(old_folder_name, file_name), 'rb')
content = old_f.read()
old_f.close()
new_f = open(r'{}/{}'.format(new_folder_name, file_name), 'wb')
new_f.write(content)
new_f.close()
# 如果拷贝完了文件,那就向队列中写入一个消息,表示已经完成
q.put(file_name)
def main():
# 1. 获取用户要copy的文件夹的名字
old_folder_name = input('请输入要copy的文件夹名:\t')
# 2. 创建一个新的文件夹
new_folder_name = '[复制]{}'.format(old_folder_name)
try:
os.mkdir(new_folder_name)
except Exception:
pass
# 3. 获取文件夹下所有文件的名字
file_names = os.listdir(old_folder_name)
# print(file_names)
# 4. 创建进程池
po = multiprocessing.Pool(5)
# 5. 创建队列
q = multiprocessing.Manager().Queue()
# 6. 向进程池里面添加 copy 文件的任务
for index, file_name in enumerate(file_names):
po.apply_async(copy_file, args=(index, file_name, old_folder_name, new_folder_name, q))
po.close() # 停止向进程池提交任务
# po.join() # 阻塞主进程,等待子进程结束
all_file_num = len(file_names) # 测量所有文件的数量
copy_file_num = 0
while True:
file_name = q.get()
# print('-----{}已经完成copy-----'.format(file_name))
copy_file_num += 1
print('\r拷贝的进度为 {:.0f}%'.format(copy_file_num/all_file_num*100), end='')
if copy_file_num == all_file_num: # 所有文件copy完成
break
print()
if __name__ == '__main__':
main()
运行结果: