Python高级
进程
os.fork
1.创建子进程方式 window不支持
2.主进程与子进程数据不共享
3.避免多次fork
Process类 跨平台方式
1. Process类 跨平台方式 from multiprocessing import Process
2. 参数: target=函数(进程要做的动作) name=进程的名字 args=(参数1,参数2,)
3. 方法:
run() --->target中指定的函数代码 但是不会启动进程
start() ---> run() ,启动新的进程
join() ----> 让主进程让步,join(1)
is_alive ---> 是否当前进程还是活着的
属性: name pid
自定义进程
步骤:
1. 创建子类继承Process
2. 重写run方法
3. 使用进程子类
案例
import os
import time
from multiprocessing import Process
# 1. 创建子类继承Process
class MyProcess(Process):
# 2. 重写run方法
def run(self):
t1=time.time()
for i in range(5):
print("i=%d,当前进程:%s,父进程:%s" % (i, self.name, os.getppid()))
time.sleep(0.01)
t2 = time.time()
print(self.name, "用时:", (t2 - t1))
# 3. 使用自定的进程子类MyProcess
if __name__ == "__main__":
# 创建进程
p = MyProcess()
p.name = "进程1"
p.start()
# 创建进程
p1 = MyProcess()
p1.name = "进程2"
p1.start()
p.join()
for n in range(5):
print("当前进程ID:%s" % (os.getpid()))
time.sleep(0.01)
进程池
1. 主进程执行任务结束,进程池中任务也结束(即使没有完成任务)
2. pool.join() # 主进程让步
3. 回调函数: 任务执行完毕之后才会调用回调函数
A》 任务中是否存在返回值 ----》回调函数的参数接收返回值
B》 回调函数必须存在一个参数接收返回值 def callback_func(n): pass
pool.apply_async
案例
import os
import time
from multiprocessing import Pool
# 1. 定义任务
def download(name):
print("即将下载:", name)
time.sleep(1)
print("下载 %s 100%%" % (name))
return name
# 2. 任务完成后
def callback_func(filename):
print(filename, "下载完毕!")
if __name__ == "__main__":
image_names = ["aa.jpg", "mm1.jpg", "美女.jpg", "flower.jpg"]
pool = Pool(3)
for image in image_names:
obj = pool.apply_async(download, args=(image,), callback=callback_func)
print(obj)
pool.close()
pool.join()
print("主进程: 所有图片下载完毕!")
阻塞式
阻塞式obj对象其实就是任务返回值
pool.apply
案例
import os
import time
from multiprocessing import Pool
# 1. 定义任务
def download(name):
print("即将下载:", name)
time.sleep(1)
print("下载 %s 100%%" % (name))
return name
if __name__ == "__main__":
image_names = ["aa.jpg", "mm1.jpg", "美女.jpg", "flower.jpg"]
pool = Pool(3)
for image in image_names:
obj = pool.apply(download, args=(image,)) # 阻塞式obj对象其实就是任务返回值
print("====>",obj)
# pool.close()
# pool.join()
print("主进程: 所有图片下载完毕!")
Queue队列
步骤:
1.导模块
multiprocessing ---》Queue
2.创建队列对象
queue=Queue(数量)
3.添加内容:
queue.put("aaa") 可以一直添加,但是满了之后就会阻塞
qu.put_nowait("hahah1") 可以一直添加,但是满了之后就会报错
queue.qsize() 获取队列中长度
4. 取内容:
queue.get() : 如果队列中没有则会阻塞,有则从队列中取出 返回值就是取出的内容
qu.get(timeout=1): 阻塞指定的时间,到时间后没有则报出异常
queue.get_nowait():有则从队列中取出 队列中没有则会报错
5. queue.empty() 返回值True,False
案例
from multiprocessing import Queue, Process
import time
# 西雅
def save(queue):
foods = ["北京烤鸭", "锅包肉", "面包", "牛奶", "麻辣烫"]
print(queue.empty())
if queue.empty():
for i in foods:
queue.put(i)
print("西雅送餐是:",i)
time.sleep(0.01)
# 玉峰
def withdraw(queue):
try:
while True:
food = queue.get(timeout=2) # 阻塞
print("很高兴哈哈哈,吃到了:", food)
except:
print("呜呜呜呜。。。。没有吃的啦。。。")
finally:
print("送餐完毕!")
if __name__ == "__main__":
# 1. 准备队列
qu = Queue(5)
# 2.准备进场
xiya = Process(target=save, args=(qu,), name="西雅")
yufeng = Process(target=withdraw, args=(qu,), name="玉峰")
xiya.start()
yufeng.start()
xiya.join()
yufeng.join()
print("主进程打印:game over!")
进程间的通信: 都是Queue作为参数传递到任务中的
1.使用Process进程 ----》 队列: Queue() --->queue对象 ---》put get qsize
2.使用的进程池 ----》队列: Manager().Queue() --->queue对象 ---》put get qsize
多进程拷贝
import os
import time
from multiprocessing import Queue, Process
def save_file(old_folder, new_folder, all_files, qu):
for file in all_files:
fr = open(old_folder + "/" + file, "r")
fw = open(new_folder + "/" + file, "w")
content = fr.read()
fw.write(content)
fr.close()
fw.close()
time.sleep(0.5)
qu.put(file)
def get_content(qu):
# while True:
# file_name = qu.get(timeout=2)
# print("复制完成:", file_name)
num = 0
while num <=length:
file_name = qu.get()
num += 1
copy_range = num / length
# %s 100%% %s %d %.1f
print("\rcopy的进度是:%.2f %%" % (copy_range * 100), end="")
if __name__ == "__main__":
old_folder = input("输入文件夹的名称:")
new_folder = old_folder + "-副本"
os.mkdir(new_folder)
all_files = os.listdir(old_folder)
print(all_files)
# 文件数量
length = len(all_files)
# 1.创建队列
qu = Queue(5)
# 2. 创建进程
p = Process(target=save_file, args=(old_folder, new_folder, all_files, qu))
p1 = Process(target=get_content, args=(qu,))
p.start()
p1.start()
p.join()
p1.join()
print("-" * 60)
总结
进程
并发 并行 串行
创建进程:
1. os.fork()
2. Process(target=函数,args=(aa,)) 扩展: 自定义的Process
3. 进程池:pool=Pool(5)
A.阻塞式 pool.apply(函数,args=(aaa))
B.非阻塞式 pool.apply_async(函数,args=(),callback=回调函数) pool.close() pool.join()
4. Queue: 进程间通信
A.Process + Queue
B.Pool + Manager().Queue()
线程
from threading import Thread 导入模块中的线程Thread类
os.getpid() 两个线程获取的是相同的进程pid
t1.start() 不能启动多次,只能启动一次
自定义线程
import os
import time
from threading import Thread
# 1. 继承Thread
class MyThread(Thread):
def __init__(self, tname, args=()):
super().__init__()
self.name = tname
# print(args)
self.args = args
# 2. 重写run()
def run(self):
if len(self.args) == 0:
print("不循环!")
else:
for i in range(self.args[0]):
print(os.getpid(), self.name, "----->", i) # os.getpid() 两个线程获取的是相同的进程pid
time.sleep(0.5)
# 创建Thread对象
if __name__ == "__main__":
t1 = MyThread("西雅", args=(1, 2))
t1.setName("小雅")
t1.start()
t2 = MyThread("西雅1")
t2.setName("小雅1")
t2.start()
多线程中全局变量在线程中共享的
from threading import Thread
import time
import os
number = 0 # 全局变量
def task(n):
global number
for i in range(10):
number += i
if n == 1:
print("---11111-->", number, i)
elif n == 2:
print("===22222===>", number, i)
time.sleep(0.5)
if __name__ == "__main__":
t1 = Thread(target=task, args=(1,))
t2 = Thread(target=task, args=(2,))
t1.start()
t2.start()
多线程中局部变量在线程中共享的
from threading import Thread
import time
import os
list1 = [] # 共享的
class Person:
pass
person = Person() # person对象 共享 ----》内存 ----》内存中属性 共享
#
def task(n):
number = 0 # 函数中声明
for i in range(3):
number += i
if n == 1:
print("---11111-->", number, i)
elif n == 2:
print("===22222===>", number, i)
person.age = n
list1.append(number)
time.sleep(0.5)
print("n----->", list1, person.age)
if __name__ == "__main__":
t1 = Thread(target=task, args=(1,))
t2 = Thread(target=task, args=(2,))
t1.start()
t2.start()
t1.join()
t2.join()
print("---主-->",person.age)
在多线程开发中:
1. 全局变量是多个线程都共享的数据;
2. 而局部变量等是各自线程的,【类属性是共享的,实例属性是非共享的 类:自定义线程类】。各个实例对象彼此间数据也是不共享的。
共享安全问题
from threading import Thread
# 全局变量
g_num = 0
def worker1():
global g_num
for i in range(1000000):
g_num += 1
print("在worker1中g_num==", g_num)
def worker2():
global g_num
for i in range(1000000):
g_num += 1
print("在worker2中g_num==", g_num)
if __name__ == "__main__":
t1 = Thread(target=worker1)
t2 = Thread(target=worker2)
t1.start()
t2.start()
t1.join()
t2.join()
print("---主-->", g_num)
1. 多个线程共同操作一个共享数据
2. 每个线程中操作共享数据的代码可能有多行
进程
os.fork
1.创建子进程方式 window不支持
2.主进程与子进程数据不共享
3.避免多次fork
Process类 跨平台方式
1. Process类 跨平台方式 from multiprocessing import Process
2. 参数: target=函数(进程要做的动作) name=进程的名字 args=(参数1,参数2,)
3. 方法:
run() --->target中指定的函数代码 但是不会启动进程
start() ---> run() ,启动新的进程
join() ----> 让主进程让步,join(1)
is_alive ---> 是否当前进程还是活着的
属性: name pid
自定义进程
步骤:
1. 创建子类继承Process
2. 重写run方法
3. 使用进程子类
案例
import os
import time
from multiprocessing import Process
# 1. 创建子类继承Process
class MyProcess(Process):
# 2. 重写run方法
def run(self):
t1=time.time()
for i in range(5):
print("i=%d,当前进程:%s,父进程:%s" % (i, self.name, os.getppid()))
time.sleep(0.01)
t2 = time.time()
print(self.name, "用时:", (t2 - t1))
# 3. 使用自定的进程子类MyProcess
if __name__ == "__main__":
# 创建进程
p = MyProcess()
p.name = "进程1"
p.start()
# 创建进程
p1 = MyProcess()
p1.name = "进程2"
p1.start()
p.join()
for n in range(5):
print("当前进程ID:%s" % (os.getpid()))
time.sleep(0.01)
进程池
1. 主进程执行任务结束,进程池中任务也结束(即使没有完成任务)
2. pool.join() # 主进程让步
3. 回调函数: 任务执行完毕之后才会调用回调函数
A》 任务中是否存在返回值 ----》回调函数的参数接收返回值
B》 回调函数必须存在一个参数接收返回值 def callback_func(n): pass
pool.apply_async
案例
import os
import time
from multiprocessing import Pool
# 1. 定义任务
def download(name):
print("即将下载:", name)
time.sleep(1)
print("下载 %s 100%%" % (name))
return name
# 2. 任务完成后
def callback_func(filename):
print(filename, "下载完毕!")
if __name__ == "__main__":
image_names = ["aa.jpg", "mm1.jpg", "美女.jpg", "flower.jpg"]
pool = Pool(3)
for image in image_names:
obj = pool.apply_async(download, args=(image,), callback=callback_func)
print(obj)
pool.close()
pool.join()
print("主进程: 所有图片下载完毕!")
阻塞式
阻塞式obj对象其实就是任务返回值
pool.apply
案例
import os
import time
from multiprocessing import Pool
# 1. 定义任务
def download(name):
print("即将下载:", name)
time.sleep(1)
print("下载 %s 100%%" % (name))
return name
if __name__ == "__main__":
image_names = ["aa.jpg", "mm1.jpg", "美女.jpg", "flower.jpg"]
pool = Pool(3)
for image in image_names:
obj = pool.apply(download, args=(image,)) # 阻塞式obj对象其实就是任务返回值
print("====>",obj)
# pool.close()
# pool.join()
print("主进程: 所有图片下载完毕!")
Queue队列
步骤:
1.导模块
multiprocessing ---》Queue
2.创建队列对象
queue=Queue(数量)
3.添加内容:
queue.put("aaa") 可以一直添加,但是满了之后就会阻塞
qu.put_nowait("hahah1") 可以一直添加,但是满了之后就会报错
queue.qsize() 获取队列中长度
4. 取内容:
queue.get() : 如果队列中没有则会阻塞,有则从队列中取出 返回值就是取出的内容
qu.get(timeout=1): 阻塞指定的时间,到时间后没有则报出异常
queue.get_nowait():有则从队列中取出 队列中没有则会报错
5. queue.empty() 返回值True,False
案例
from multiprocessing import Queue, Process
import time
# 西雅
def save(queue):
foods = ["北京烤鸭", "锅包肉", "面包", "牛奶", "麻辣烫"]
print(queue.empty())
if queue.empty():
for i in foods:
queue.put(i)
print("西雅送餐是:",i)
time.sleep(0.01)
# 玉峰
def withdraw(queue):
try:
while True:
food = queue.get(timeout=2) # 阻塞
print("很高兴哈哈哈,吃到了:", food)
except:
print("呜呜呜呜。。。。没有吃的啦。。。")
finally:
print("送餐完毕!")
if __name__ == "__main__":
# 1. 准备队列
qu = Queue(5)
# 2.准备进场
xiya = Process(target=save, args=(qu,), name="西雅")
yufeng = Process(target=withdraw, args=(qu,), name="玉峰")
xiya.start()
yufeng.start()
xiya.join()
yufeng.join()
print("主进程打印:game over!")
进程间的通信: 都是Queue作为参数传递到任务中的
1.使用Process进程 ----》 队列: Queue() --->queue对象 ---》put get qsize
2.使用的进程池 ----》队列: Manager().Queue() --->queue对象 ---》put get qsize
多进程拷贝
import os
import time
from multiprocessing import Queue, Process
def save_file(old_folder, new_folder, all_files, qu):
for file in all_files:
fr = open(old_folder + "/" + file, "r")
fw = open(new_folder + "/" + file, "w")
content = fr.read()
fw.write(content)
fr.close()
fw.close()
time.sleep(0.5)
qu.put(file)
def get_content(qu):
# while True:
# file_name = qu.get(timeout=2)
# print("复制完成:", file_name)
num = 0
while num <=length:
file_name = qu.get()
num += 1
copy_range = num / length
# %s 100%% %s %d %.1f
print("\rcopy的进度是:%.2f %%" % (copy_range * 100), end="")
if __name__ == "__main__":
old_folder = input("输入文件夹的名称:")
new_folder = old_folder + "-副本"
os.mkdir(new_folder)
all_files = os.listdir(old_folder)
print(all_files)
# 文件数量
length = len(all_files)
# 1.创建队列
qu = Queue(5)
# 2. 创建进程
p = Process(target=save_file, args=(old_folder, new_folder, all_files, qu))
p1 = Process(target=get_content, args=(qu,))
p.start()
p1.start()
p.join()
p1.join()
print("-" * 60)
总结
进程
并发 并行 串行
创建进程:
1. os.fork()
2. Process(target=函数,args=(aa,)) 扩展: 自定义的Process
3. 进程池:pool=Pool(5)
A.阻塞式 pool.apply(函数,args=(aaa))
B.非阻塞式 pool.apply_async(函数,args=(),callback=回调函数) pool.close() pool.join()
4. Queue: 进程间通信
A.Process + Queue
B.Pool + Manager().Queue()
线程
from threading import Thread 导入模块中的线程Thread类
os.getpid() 两个线程获取的是相同的进程pid
t1.start() 不能启动多次,只能启动一次
自定义线程
import os
import time
from threading import Thread
# 1. 继承Thread
class MyThread(Thread):
def __init__(self, tname, args=()):
super().__init__()
self.name = tname
# print(args)
self.args = args
# 2. 重写run()
def run(self):
if len(self.args) == 0:
print("不循环!")
else:
for i in range(self.args[0]):
print(os.getpid(), self.name, "----->", i) # os.getpid() 两个线程获取的是相同的进程pid
time.sleep(0.5)
# 创建Thread对象
if __name__ == "__main__":
t1 = MyThread("西雅", args=(1, 2))
t1.setName("小雅")
t1.start()
t2 = MyThread("西雅1")
t2.setName("小雅1")
t2.start()
多线程中全局变量在线程中共享的
from threading import Thread
import time
import os
number = 0 # 全局变量
def task(n):
global number
for i in range(10):
number += i
if n == 1:
print("---11111-->", number, i)
elif n == 2:
print("===22222===>", number, i)
time.sleep(0.5)
if __name__ == "__main__":
t1 = Thread(target=task, args=(1,))
t2 = Thread(target=task, args=(2,))
t1.start()
t2.start()
多线程中局部变量在线程中共享的
from threading import Thread
import time
import os
list1 = [] # 共享的
class Person:
pass
person = Person() # person对象 共享 ----》内存 ----》内存中属性 共享
#
def task(n):
number = 0 # 函数中声明
for i in range(3):
number += i
if n == 1:
print("---11111-->", number, i)
elif n == 2:
print("===22222===>", number, i)
person.age = n
list1.append(number)
time.sleep(0.5)
print("n----->", list1, person.age)
if __name__ == "__main__":
t1 = Thread(target=task, args=(1,))
t2 = Thread(target=task, args=(2,))
t1.start()
t2.start()
t1.join()
t2.join()
print("---主-->",person.age)
在多线程开发中:
1. 全局变量是多个线程都共享的数据;
2. 而局部变量等是各自线程的,【类属性是共享的,实例属性是非共享的 类:自定义线程类】。各个实例对象彼此间数据也是不共享的。
共享安全问题
from threading import Thread
# 全局变量
g_num = 0
def worker1():
global g_num
for i in range(1000000):
g_num += 1
print("在worker1中g_num==", g_num)
def worker2():
global g_num
for i in range(1000000):
g_num += 1
print("在worker2中g_num==", g_num)
if __name__ == "__main__":
t1 = Thread(target=worker1)
t2 = Thread(target=worker2)
t1.start()
t2.start()
t1.join()
t2.join()
print("---主-->", g_num)
1. 多个线程共同操作一个共享数据
2. 每个线程中操作共享数据的代码可能有多行