前言
本文将和大家一起探讨python并发编程的实际运用,会以一些我实际使用的案例,或者一些典型案例来分享。本文使用的案例是我实际使用的案例(上篇),是基于之前效率不高的代码改写成并发编程的。让我们来看看改造的过程,这样就会对并发编程的高效率有个清晰地认知,也会在改造过程中学到一些知识。
本文为python并发编程的第十六篇,上一篇文章地址如下:
python:并发编程(十五)_Lion King的博客-CSDN博客
下一篇文章地址如下:
python:并发编程(十七)_Lion King的博客-CSDN博客
一、改造对象
1、案例地址
python:根据灰度值检查成像是否存在黑图情况_python 判断图片是否有黑边_Lion King的博客-CSDN博客
import os
from PIL import Image
def image_gray(img):
# 打开图片
img = Image.open(img)
# 计算平均灰度值
gray_sum = 0
count = 0
for x in range(img.width):
for y in range(img.height):
if img.mode == "RGB":
r, g, b = img.getpixel((x, y))
gray_sum += (r + g + b) / 3
elif img.mode == "L":
gray_value = img.getpixel((x, y))
gray_sum += gray_value
count += 1
avg_gray = gray_sum / count
return avg_gray
def find_image(folder_path):
# 定义一个列表存储图片路径
images = []
# 遍历文件夹下的所有文件
for root, dirs, files in os.walk(folder_path):
for file in files:
file_path = os.path.join(root, file)
# 处理每个文件,将其添加到列表中
images.append(file_path)
return images
def assert_run(folder_path):
images=find_image(folder_path)
for img in images:
gray = image_gray(img)
# 灰度值小于50,将认为是黑图
if gray < 50:
print(img, ":", gray)
if __name__ == "__main__":
# image_gray()
# find_image()
folder_path = r'D:\黑图'
assert_run(folder_path)
这里简单介绍一下这段代码:这段代码是一个简单的图像处理程序,用于找出指定文件夹中的黑图像。代码首先定义了一个image_gray
函数,用于计算图像的平均灰度值。然后定义了一个find_image
函数,用于遍历指定文件夹下的所有文件,并返回图像文件的路径列表。最后,在assert_run
函数中,使用find_image
函数获取指定文件夹中的图像路径列表,并对每个图像调用image_gray
函数计算平均灰度值,如果平均灰度值小于50,则打印该图像的路径和灰度值。
整体流程如下:
(1)导入必要的模块:os
用于操作文件和文件夹,PIL
用于图像处理。
(2)定义image_gray
函数:打开图像文件,计算图像的平均灰度值。
(3)定义find_image
函数:遍历指定文件夹下的所有文件,返回图像文件的路径列表。
(4)定义assert_run
函数:调用find_image
函数获取指定文件夹中的图像路径列表,对每个图像调用image_gray
函数计算平均灰度值,如果小于50则打印图像路径和灰度值。
(5)在if __name__ == "__main__":
代码块中,指定一个文件夹路径作为参数,调用assert_run
函数执行图像处理。
请注意,代码中使用了PIL
库来处理图像,确保你已经安装了该库,可以使用pip install Pillow
来安装。此外,要确保指定的文件夹中包含图像文件,并且文件的格式受PIL
库支持。
2、性能问题排查
为方便排查性能问题,我们需要在上面代码的基础上加一个计算耗时的装饰器,程序如下:
def calculate_runtime(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
runtime = end_time - start_time
print(f"程序运行时间:{runtime}秒")
return result
return wrapper
(1)先测算assert_run函数的时间,即整体时间。如下图,485张图片耗时约1933秒,约32分钟左右处理完这些图片。
(2)再测算image_gray函数的时间,即处理一张图的时间,大概需要4秒左右。
(3)接着测算将图片假如列表的时间,几乎可以忽略不计。
综上,处理一张图需要的时间很长,这是导致整个脚本运行时间很长的根本原因。因此,优化的点应该是使用并发编程同时处理多个图片、使用并发编程处理一个图片的灰度值、解决一个图片耗时长的问题(如用更快的模块来处理灰度值)。
二、实施方案:使用多进程同时处理多个图片
虽然直接解决一个图片的耗时,能够让这个任务时间瞬间变短很多,但是,为了方便观察耗时,我们先让处理一张图片的时间保持为4秒左右,基于这个,我们采用并发编程的方式,优化整体时间。
1、先修改代码,让其处理4张图片,方便调试
2、改造 assert_run 函数为多进程并发
import os
from PIL import Image
import time
import concurrent.futures
def calculate_runtime(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
runtime = end_time - start_time
print(f"程序运行时间:{runtime}秒")
return result
return wrapper
@calculate_runtime
def image_gray(img):
# 打开图片
img = Image.open(img)
# 计算平均灰度值
gray_sum = 0
count = 0
for x in range(img.width):
for y in range(img.height):
if img.mode == "RGB":
r, g, b = img.getpixel((x, y))
gray_sum += (r + g + b) / 3
elif img.mode == "L":
gray_value = img.getpixel((x, y))
gray_sum += gray_value
count += 1
avg_gray = gray_sum / count
return avg_gray
@calculate_runtime
def find_image(folder_path):
# 定义一个列表存储图片路径
images = []
# 遍历文件夹下的所有文件
for root, dirs, files in os.walk(folder_path):
for file in files:
file_path = os.path.join(root, file)
# 处理每个文件,将其添加到列表中
images.append(file_path)
return images[0:4]
def process_image(img):
gray = image_gray(img)
# 灰度值小于50,将认为是黑图
if gray < 50:
print(img, ":", gray)
@calculate_runtime
def assert_run(folder_path):
images = find_image(folder_path)
with concurrent.futures.ProcessPoolExecutor(max_workers=10) as executor:
# 提交任务并发执行
futures = [executor.submit(process_image, img) for img in images]
# 等待所有任务完成
concurrent.futures.wait(futures)
if __name__ == "__main__":
folder_path = r'C:\Users\yeqinfang\Desktop\临时文件\文件存储'
assert_run(folder_path)
处理4张图片时,在没有采用多进程的情况下,脚本运行需要16秒,改了多进程(启用10个进程)后,运行时间为5秒左右。
3、一些小实验
不同进程处理40张图片的耗时情况,如下几个图片:
1个进程时,40张图片耗时 192 秒
5个进程时,40张图片耗时 46 秒
10个进程时,40张图片耗时 38 秒
15个进程时,40张图片耗时 38 秒
20个进程时,40张图片耗时 38 秒
60个进程时,40张图片耗时 44 秒
这样的现象是不是有点意思呢?后续文章我们再对其进行分析,我们先简单了解一下咋们的系统,看一下我系统的内核数量,可执行cmd指令:
wmic cpu get NumberOfCores
显示的内核储量为6,在一个具有6个物理内核的系统上,并发执行的进程数量通常应该小于或等于物理内核的数量。这是因为每个物理内核都可以独立执行一个进程,同时超过物理内核数量的进程可能会导致竞争和性能下降。
但需要注意的是,并发执行的进程数量还受到其他因素的影响,如系统负载、资源需求等。在决定并发执行的进程数量时,需要综合考虑系统的性能和资源利用情况。可以根据实际情况进行测试和调整,观察并发执行不同数量进程时的性能表现,选择最优的进程数量。
4、使用10个进程处理485张图片
在没有使用并发之前,我们处理485张图片耗时约1933秒,约32分钟左右处理完这些图片。
在使用多进程并发之后,我们处理485张图片耗时约481秒,约8分钟左右处理完这些图片。
这种情况,多进程就有话说了:普通编程编不了的程,由我多进程来编,还有,你听好,普通编程不敢编的程我编,普通编程不敢管的事我管,一句话,普通编程管得了的我要管,普通编程管不了的我更要管,这就是多进程,够不够清楚!文章来源:https://www.toymoban.com/news/detail-490050.html
文章来源地址https://www.toymoban.com/news/detail-490050.html
到了这里,关于python:并发编程(十六)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!