实现多任务的另一种形式
程序是可以运行的,运行起来叫做进程,能够分配各种资源。(网络、显卡、鼠标、键盘、蓝牙…)
程序只有一个,但是进程可以多个。
使用进程实现多任务
import time
import multiprocessing
def test1():
while True:
print('----1-----')
time.sleep(1)
def test2():
while True:
print('----2-----')
time.sleep(1)
def main():
p1 = multiprocessing.Process(target=test1)
p2 = multiprocessing.Process(target=test2)
p1.start()
p2.start()
if __name__ == '__main__':
main()
可以看出,进程和我们学过的线程 效果是一样的。
在ubuntu 中查看所有进程
ps -aux
进程 和 线程 都能实现多任务,但是进程占用的资源比较大。
进程和线程的区别:
线程不能独立执行,必须已存在进程中。
可以将进程理解为工厂中的一条流水线,而其中的线程就是这个流水线上的工人。
一个程序至少有一个进程,一个进程至少有一个线程。
线程的划分尺度小于进程,使得多线程程序的并发性高。
进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。比如:
网易云和天天静听 是两个进程,同时打开就是多进程,在每个进程中,既可以播放音乐,同时又能下载音乐,这就是多线程。
线程之间共享数据,但是进程是独立的,所以进程之间主需要通信。–队列
队列:先进先出–Queue
栈:先进后出
解耦:避免两个程序之间联系太过密切。
多进程之间通过Queue 来实现数据共享:
import multiprocessing
def download_from_web(q):
'''下载数据'''
data = [1, 2, 3]
# 向队列中写诶数据
for i in data:
q.put(i)
print('---下载器已经下载完了数据,并且写入队列中')
def analysis_data(q):
'''数据处理'''
waitting_data = list()
# 从队列中获取数据
while True:
data = q.get()
waitting_data.append(data)
if q.empty():
break
# 模拟数据处理
print(waitting_data)
def main():
# 创建一个队列
q = multiprocessing.Queue()
p1 = multiprocessing.Process(target=download_from_web, args=(q,))
p2 = multiprocessing.Process(target=analysis_data, args=(q,))
p1.start()
p2.start()
if __name__ == '__main__':
main()
任务数确定,创建对应的进程就可以,当任务数不确定,创建进程池。
这个程序 ,我在windows 上的pycharm 没有实现。不知道为啥。
本应该的运行结果:
from multiprocessing import Pool
import os, time, random
def worker(msg):
t_start = time.time()
print('%s开始执行,进程号:%d' % (msg, os.getpgid()))
# random.random() 随机生成0-1之间的浮点数
time.sleep(random.random()*2)
t_stop = time.time()
print(msg, '执行完毕,耗时%0.2f' % (t_start - t_stop))
def main():
po = Pool(3) # 创建一个进程池,最大进程数3
for i in range(0,10):
# Pool().apply.async(要调用的目标,(传递给目标的参数元祖,))
# 每次循环都会用空闲出来的子进程去调用目标
po.apply_async(worker,(i,))
print('----start---')
po.close() # 关闭进程池,关闭后po 不在接收新的请求
po.join() # 等待po 中所有子进程执行完成,必须放在close之后,保证主进程运行时间大于子进程。
print('----end-----')
if __name__ == '__main__':
main()
多任务文件夹拷贝:
import os
import multiprocessing
def copy_file(q, file_name, old_folder_name, new_folder_name):
'''完成文件的复制'''
old_f = open(old_folder_name + '/' + file_name, 'rb') # 路径,用 / 连接
content = old_f.read()
old_f.close()
new_f = open(new_folder_name + '/' + file_name, 'wb')
new_f.write(content)
new_f.close()
# 如果拷贝完了文件,那么就向队列中写入一个消息,表示已经完成
q.put(file_name)
def main():
# 1. 获取用户要拷贝的文件夹的名字
old_folder_name = input('请输入要复制的文件夹的名字:')
# 2. 创建一个新的文件夹
try:
new_folder_mame = old_folder_name + '[复件]'
os.mkdir(new_folder_mame)
except:
pass
# 3. 获取文件夹中所有文件的名字 listdir()
file_names = os.listdir(old_folder_name)
# print(old_folder_name)
# 4. 创建进程池
po = multiprocessing.Pool(5)
# 5. 创建一个队列
q = multiprocessing.Manager().Queue()
# 向进程池中添加 copy 文件的任务
for file_name in file_names:
po.apply_async(copy_file,args=(q, file_name, old_folder_name, new_folder_mame))
po.close()
# po.join()
all_file_num = len(file_names) # 测一下文件个数
copy_num = 0
while True:
file_name = q.get()
# print('已经完成拷贝: %s' % file_name)
copy_num += 1
print('拷贝的进度为 %.2f %%' % (copy_num * 100 / all_file_num),end='\r') # \r 表示一直都在顶行显示
if copy_num >= all_file_num:
break
print()
if __name__ == '__main__':
main()
在运行中遇到很多问题,
- 要复制的文件夹必须在工程下,否则找不到路径
- 要复制的文件夹中不能再包含文件夹,否则程序一直不结束。
但是,不成功的地方也有,想要在一行显示进度条,但是不知道为啥不成功。
大概是这样的效果:进度从0变到100,只更新不换行。
1