文章目录

  • 需求
  • 实现
    • 先导入本次需要用到的包
    • 一些辅助函数
      • 如下函数是得到指定后缀的文件
      • 如下的函数一个是读图像,一个是把RGB转成BGR
    • 下面是主要的几个处理函数
    • 在上面几个函数构建对应的处理函数
    • main函数
    • 按顺序执行
  • 结果

需求

本次的需求是边读图像,边处理图像(各种变组合),处理完后还要把处理好的图像保存到指定的文件夹。而且图像也挺多的,如果按顺序一个一个处理,那肯定要不少时间。所以就想到了多线程并发编程。

实现

先导入本次需要用到的包

import os
import threading
from queue import Queue
import cv2

一些辅助函数

如下函数是得到指定后缀的文件

IMG_EXTENSIONS = ('.jpg', '.jpeg', '.png', '.ppm', '.bmp', '.pgm', '.tif', '.tiff', '.webp')def get_all_files(base, extensions):"""get all files in extensions from base folder, it's a generator"""for root, _, files in sorted(os.walk(base, followlinks=True)):for file in sorted(files):if file.endswith(extensions):yield os.path.join(root, file)def get_all_images(base, image_extensions):"""get all images"""return get_all_files(base, image_extensions)

如下的函数一个是读图像,一个是把RGB转成BGR

def default_loader_cv2(path):return cv2.cvtColor(cv2.imread(path), cv2.COLOR_BGR2RGB)def rgb_2_bgr(img):return cv2.cvtColor(img, cv2.COLOR_RGB2BGR)

下面是主要的几个处理函数

def load_image(target_dir, source_file):"""load image here"""target_file = get_save_path(target_dir, source_file)img = default_loader_cv2(source_file)return (target_file, img)def transform(stain_normalizer, img):"""Description:- transform image method, basic resize here, you could do other transform here"""return cv2.resize(img, (256, 256))def save(save_path, img):"""save image method"""cv2.imwrite(save_path, rgb_2_bgr(img))

在上面几个函数构建对应的处理函数

def do_load_image(load_queue: Queue, trainsform_queue: Queue, target_dir:str):while True:file = load_queue.get()if file is None: breaktarget_file = os.path.join(target_dir, source_file)if not os.path.exists(target_file):      # skip all the transformed imagesimg = default_loader_cv2(file)trainsform_queue.put((target_file, img))else:passdef do_transforms(trainsform_queue: Queue, save_queue: Queue, stain_normalizer):while True:data = trainsform_queue.get()if data is None: breaktarget_file, img = dataimg_norm = transform(stain_normalizer, img)save_queue.put((target_file, img_norm))def do_save(save_queue:Queue):while True:data = save_queue.get()if data is None:  breaktarget_file, img_norm = datasave(target_file, img_norm)

main函数

在这里,是整个程度的启动,特别注意线程的启动与结束顺序,不要搞错了,不然程序会进行死循环。
一般生产者消费者,大家看到的都是只有两个函数(一个生产者,一个消费者),这里实行的是3个函数,load是transform的生产者,transform是save的生产者,这里利用队列实行了3个队列,实行了数据间的传递。可以利用这种思想实行更多层级的生产者与消费者模式。

def main(source_dir, target_dir):# 4104 image, took 224.6297sfiles = get_all_images(source_dir, IMG_EXTENSIONS)  # generator could only be iterated 1 time# transform will be the slowest, so load queue would be too much data if you donot maximizeload_queue = Queue(maxsize=5000) trainsform_queue = Queue()save_queue = Queue()for file in files:load_queue.put(file)# start load_threadsload_threads = []for _ in range(2):t = threading.Thread(target=do_load_image,args=(load_queue, trainsform_queue, target_dir))t.start()load_threads.append(t)# start transform_threadstransform_threads = []for _ in range(6):t = threading.Thread(target=do_transforms,args=(trainsform_queue, save_queue, stain_normalizer))t.start()transform_threads.append(t)# start save_threadssave_threads = []for _ in range(4):t = threading.Thread(target=do_save,args=(save_queue,))t.start()save_threads.append(t)# put sentinel load_threads to break the loop# DONOT put thread.join() under this loopfor _ in load_threads:load_queue.put(None)for thread in load_threads:thread.join()# put sentinel transform_threads to break the loop# DONOT put thread.join() under this loopfor thread in transform_threads:trainsform_queue.put(None)for thread in transform_threads:thread.join()# put sentinel transform_threads to break the loop# DONOT put thread.join() under this loopfor thread in save_threads:save_queue.put(None)for thread in save_threads:thread.join()

按顺序执行

def single_thread(source_dir, target_dir):# 4104 image, took 486.4547sfiles = get_all_images(source_dir, IMG_EXTENSIONS)for file in files:target_file, img = load_image(target_dir, file)img_transform = transform(stain_normalizer, img)save(target_file, img_transform)

结果

从代码来看,单线程的顺序执行比多线程少不小的代码,而且结果也相对简单,基本上不会出什么问题。然后单线程的所要花费的时间却是多线程的2倍还要多。图像一共是4104张512x512的3通道png图像。单线程花费时间是486.4547s,而多线程花费时间是224.6297s。是虽然多线程的代码多了点,但是从性能上来说,还是比单线程顺序执行快不少,还是蛮值得的

python 多线程并发编程(生产者、消费者模式),边读图像,边处理图像,处理完后保存图像实现提高处理效率相关推荐

  1. [19/04/11-星期四] 多线程_并发协作(生产者/消费者模式_2种解决方案(管程法和信号灯法))...

    一.概念 多线程环境下,我们经常需要多个线程的并发和协作.这个时候,就需要了解一个重要的多线程并发协作模型"生产者/消费者模式". Ø 什么是生产者? 生产者指的是负责生产数据的模 ...

  2. Java多线程(含生产者消费者模式详解)

    多线程 导航 多线程 1 线程.进程.多线程概述 2 创建线程 (重点) 2.1 继承Thread类(Thread类也实现了Runnable接口) 2.2 实现Runnable接口(无消息返回) 2. ...

  3. java多线程抽奖_java 线程池、多线程并发实战(生产者消费者模型 1 vs 10) 附案例源码...

    导读 前二天写了一篇<Java 多线程并发编程>点我直达,放国庆,在家闲着没事,继续写剩下的东西,开干! 线程池 为什么要使用线程池 例如web服务器.数据库服务器.文件服务器或邮件服务器 ...

  4. python多线程问题及生产者消费者示例

    多线程能干什么: 生产者消费者问题: 一直生产,一直消费,中间有阀值,避免供求关系不平衡,导致出现问题. #线程安全问题,要是线程同时来,听谁的 #锁:一种数据结构 队列:先进线出 栈:先进后出1.解 ...

  5. mysql服务器多线程模型_java 线程池、多线程并发实战(生产者消费者模型 1 vs 10) 附案例源码 - 陈彦斌 - 博客园...

    导读 前二天写了一篇<Java 多线程并发编程>点我直达,放国庆,在家闲着没事,继续写剩下的东西,开干! 线程池 为什么要使用线程池 例如web服务器.数据库服务器.文件服务器或邮件服务器 ...

  6. Java多线程:解决生产者/消费者模式

    什么是生产者/消费者模式 生产者消费者模型具体来讲,就是在一个系统中,存在生产者和消费者两种角色,他们通过内存缓冲区进行通信,生产者生产消费者需要的资料,消费者把资料做成产品. 具体来说就是: 生产者 ...

  7. Java 并发(生产者/消费者 模式)

    >生产者/消费者 模式角色:生产者,消费者都是线程,两者中间是容器,容器内部是产品. 要求: 容器 里面要定义容量 容器 往里面添加(满时等待) 或者 从里面删除(空时等待) ,都要是阻塞的(等 ...

  8. Python多线程并发编程

    一.Python中的GIL """ GIL的全称global interpreter lock 意为全局解释器锁. Python中的一个线程对应与c语言中的一个线程. G ...

  9. python多线程并发编程技术_同步线程 - Python并发编程教程™

    线程同步可以定义为一种方法,借助这种方法,可以确信两个或更多的并发线程不会同时访问被称为临界区的程序段. 另一方面,正如我们所知道的那样,临界区是共享资源被访问的程序的一部分. 因此,同步是通过同时访 ...

最新文章

  1. PHP实现上一篇、下一篇
  2. angular中的class写三元表达式 和 清空表单校验
  3. Java开发人员应该知道的5种错误跟踪工具
  4. Oracle 12.1.0.1 GI+DATABASE打PSU
  5. ab压力测试php脚本,ab压力测试工具-批量压测脚本
  6. selenium模拟登陆去哪儿网
  7. 吐血整理!顶级程序员的百宝箱来咯!| 原力计划
  8. ftp服务器通常提供文件上传和,基于FTPClient的文件上传至Nginx服务器
  9. 【王道计组笔记】I/O输入输出系统基本概念
  10. js获取浏览器内核版本信息
  11. 前缀和差分 精讲(一维、二维、附例题!)
  12. 现行高考政策公平 辩论_辩论文:现行高考模式有(不)利于选拔入才
  13. Linux递归修改后缀名
  14. 移动办公模式下的业务 微易聊微信管理系统作用显著!
  15. 图书管理系统(归还书籍)
  16. 微信小程序的设计以及demo
  17. Vue3中使用Ant Design Vue图标
  18. 通过证书管理解决无法连接 Citrix XenApp SSL 61 您还未选择信任证书颁发者的问题
  19. 失落世界服务器国庆宝箱位置,烟雨江湖国庆宝箱在哪里 烟雨江湖中秋宝箱位置坐标大全...
  20. Python入门 类型转换

热门文章

  1. ES6学习笔记(二十二)ArrayBuffer
  2. MTK-TP(电阻屏校准程序ts_lib移植)
  3. Linux下安装zookeeper集群(奇数个)
  4. caffe 中的一些参数介绍
  5. iOS 开发--github的demo
  6. ichat在线客服jQuery插件(可能是历史上最灵活的)
  7. C语言宏定义##连接符和#符的使用及其它宏定义注意事项
  8. 微信小程序——解决上传并部署云函数时报错ResourceNotFound.Function, 未找到函数版本,请创建后再试。 (7f2d9d2d-5eac-4575-9n57-acd66cfa587g
  9. Webpack进阶(一) tree shaking与不同mode
  10. 青海省多地日降水量突破历史极值