- 程序运行起来后,代码+用到的资源,称之为
进程
。它是操作系统分配资源的基本单元。 - 进程和线程:
进程
,能够完成多任务,比如 在一台电脑上能够同时运行多个QQ
线程
,能够完成多任务,比如 一个QQ中的多个聊天窗口
定义不同
进程是系统进行资源分配和调度的一个独立单位.
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
yy_01_使用进程实现多任务
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()
yy_02_获取进程的pid
import multiprocessing
import os
def run_proc():
"""子进程要执行的代码"""
print("子进程的进程号 pid=%d---" % os.getpid()) # os.getpid()获取当前进程的进程号
def main():
print("父进程的进程号 pid=%d---" % os.getpid())
p1 = multiprocessing.Process(target=run_proc)
p1.start()
if __name__ == '__main__':
main()
yy_03_进程的运行顺序
import time
import multiprocessing
def test1():
for i in range(5):
print("----进程1-----")
def test2():
for i in range(5):
print("----进程2-----")
def main():
p1 = multiprocessing.Process(target=test1)
p2 = multiprocessing.Process(target=test2)
p1.start()
time.sleep(1)
p2.start()
time.sleep(1)
print("主进程")
if __name__ == "__main__":
main()
yy_04_给子进程函数传递参数
import multiprocessing
import time
import os
def run_proc(*arg, **kw):
"""子进程要执行的代码"""
for i in range(5):
print("子进程的进程号 pid=%d---" % os.getpid()) # os.getpid()获取当前进程的进程号
print("%s:%s" % arg)
print("key:%s, " % kw)
def main():
print("父进程的进程号 pid=%d---" % os.getpid())
p1 = multiprocessing.Process(target=run_proc, args=('test',18), kwargs={"yy":20})
p1.start()
# p1.terminate()
p1.join() # join 等子线程运行在往下运行
print("主线程")
if __name__ == '__main__':
main()
yy_05_多进程间不共享全局变量
import time
import multiprocessing
gl_num = 100
gl_list = [1, 2]
def test1():
print("----11111-----")
print(gl_list)
gl_list.append(333)
global gl_num
gl_num += 100
print(gl_num)
time.sleep(1)
print(gl_list)
def test2():
print("----22222-----")
print(gl_list)
gl_list.append(666)
global gl_num
gl_num += 200
print(gl_num)
time.sleep(1)
print(gl_list)
def main():
p1 = multiprocessing.Process(target=test1)
p2 = multiprocessing.Process(target=test2)
p1.start()
p1.join()
p2.start()
p2.join()
print("主进程里的gl_list=%s" % gl_list)
print("主进程里的gl_num=%s" % gl_num)
if __name__ == "__main__":
main()
yy_06_通过队列(Queue)完成多进程间通信
import multiprocessing
def down_data(q):
"""下载数据"""
down_list = [1, 88, 66, True, "Apple"]
for i in down_list:
q.put(i)
print("下载完毕,数据已经保存到列表中...")
def recvfrom_data(q):
"""下载数据到本地"""
recvfrom_list = list() # 创建一个空列表[] = list()
while True:
data = q.get()
recvfrom_list.append(data)
if q.empty():
break
print(recvfrom_list)
def main():
# 1.创建一个队列
q = multiprocessing.Queue()
# 2.创建多个进程,将队列引用当作实参传递给函数
p1 = multiprocessing.Process(target=down_data, args=(q,))
p2 = multiprocessing.Process(target=recvfrom_data, args=(q,))
p1.start()
p2.start()
if __name__ == '__main__':
main()
- 未完待续
- 一般任务比较多时,使用
进程池
,如果只是一两个进程,直接创建就好了。 - 不确定有多个进程用
进程池
。 - 通过Process创建的多进程和多线程一样,主进程会等子进程运行完在结束程序。
- 而通过进程池创建的程序,主程序不会等子进程运行完,在结束程序。所以需要给住进程田间阻塞。
pool.close()
pool.join()
yy_07_进程池Pool
import multiprocessing
import os, time, random
def works(msg):
t_start = time.time()
print("子进程%d:开始执行,进程号:%d" % (msg, os.getpid()))
# random.random()随机生成0~1之间的浮点数
time.sleep(random.random()*2)
t_end = time.time()
print("子进程:%d,运行结束,耗时:%.2f" % (os.getpid(), t_end-t_start))
def main():
po = multiprocessing.Pool(3) # 定义一个进程池,最大进程数3,此时还没有创建子进程,调用目标时才创建
for i in range(0,10):
# po.apply_async(要调用的目标, (要传递参数元组,))
# 通过循环会创建出10个要调用的目标,存放在内存中
# 但是进程池中只有三个子进程,系统会自动分配这10个调用目标到3个子进程中
# 当这3个进程在运行时,其他调用目标等待
# 有空位出现,调用目标补上,知道运行完所有调用目标
po.apply_async(works, (i,))
print("---start---")
po.close() # 关闭进程池,关闭后po不再接收新的请求
po.join() # 等待po中所有子进程运行完,必须放在close语句后面
print("---end---")
if __name__ == '__main__':
main()
yy_08_案例:多任务文件夹copy
import os
import multiprocessing
def copy_file(file_name, old_copy_name, new_copy_name):
"""复制文件"""
# print("要拷贝的文件%s" % file_name)
# 以只读的方式打开源文件
read_file = open(old_copy_name + "/" + file_name, "rb")
read_flie_data = read_file.read()
read_file.close()
# 以写入方式打开进行写入文件
write_file = open(new_copy_name + "/" + file_name, "wb")
write_file.write(read_flie_data)
write_file.close()
def main():
# 输入要拷贝的文件夹
old_copy_name = input("请输入要拷贝的文件夹:")
# 获取文件夹下的所有文件名 os.listdir
file_names = os.listdir("./" + old_copy_name)
# print(file_names)
# 创建新的文件夹用来保存
try:
new_copy_name = old_copy_name + "[复件]"
os.mkdir(new_copy_name)
except:
pass
# 创建进程池
po = multiprocessing.Pool(5)
# 向进程池中添加任务
for file_name in file_names:
po.apply_async(copy_file, args=(file_name, old_copy_name, new_copy_name))
po.close()
po.join()
if __name__ == '__main__':
main()
- 如果要使用Pool创建进程,就需要使用multiprocessing.Manager()中的Queue(),而不是multiprocessing.Queue()
yy_09_案例:升级多任务文件夹copy(可显示进度)
import os
import multiprocessing
def copy_file(q, file_name, old_copy_name, new_copy_name):
"""复制文件"""
# print("要拷贝的文件%s" % file_name)
# 以只读的方式打开源文件
read_file = open(old_copy_name + "/" + file_name, "rb")
read_flie_data = read_file.read()
read_file.close()
# 以写入方式打开进行写入文件
write_file = open(new_copy_name + "/" + file_name, "wb")
write_file.write(read_flie_data)
write_file.close()
# 如果拷贝完了文件就向列表中添加一个消息,表示完成
q.put(file_name)
def main():
while True:
# 输入要拷贝的文件夹
old_copy_name = input("请输入要拷贝的文件夹:")
# 获取文件夹下的所有文件名 os.listdir
try:
file_names = os.listdir("./" + old_copy_name)
break
except FileNotFoundError:
print("没有找到该文件")
# 创建新的文件夹用来保存
try:
new_copy_name = old_copy_name + "[复件]"
os.mkdir(new_copy_name)
except:
pass
# 创建进程池
po = multiprocessing.Pool(5)
# 创建队列
q = multiprocessing.Manager().Queue()
# 向进程池中添加任务
for file_name in file_names:
po.apply_async(copy_file, args=(q, file_name, old_copy_name, new_copy_name))
po.close()
# po.join()
num = len(file_names) # 测一下所有文件个数
nums = 0
while True:
ge = q.get()
nums += 1
print("\r已完成%.2f %%" % (nums*100/num), end="")
if nums >= num:
break
print("")
if __name__ == '__main__':
main()