python多线程方法详解


Posted in Python onJanuary 18, 2022

处理多个数据和多文件时,使用for循环的速度非常慢,此时需要用多线程来加速运行进度,常用的模块为multiprocess和joblib,下面对两种包我常用的方法进行说明。

1、模块安装

pip install multiprocessing
pip install joblib

2、以分块计算NDVI为例

首先导入需要的包

import numpy as np
from osgeo import gdal
import time
from multiprocessing import cpu_count
from multiprocessing import Pool
from joblib import Parallel, delayed

定义GdalUtil类,以读取遥感数据

class GdalUtil:
    def __init__(self):
        pass
    @staticmethod
    def read_file(raster_file, read_band=None):
        """读取栅格数据"""
        # 注册栅格驱动
        gdal.AllRegister()
        gdal.SetConfigOption('gdal_FILENAME_IS_UTF8', 'YES')
        # 打开输入图像
        dataset = gdal.Open(raster_file, gdal.GA_ReadOnly)
        if dataset == None:
            print('打开图像{0} 失败.\n', raster_file)
        # 列
        raster_width = dataset.RasterXSize
        # 行
        raster_height = dataset.RasterYSize
        # 读取数据
        if read_band == None:
            data_array = dataset.ReadAsArray(0, 0, raster_width, raster_height)
        else:
            band = dataset.GetRasterBand(read_band)
            data_array = band.ReadAsArray(0, 0, raster_width, raster_height)
        return data_array
 
    @staticmethod
    def read_block_data(dataset, band_num, cols_read, rows_read, start_col=0, start_row=0):
        band = dataset.GetRasterBand(band_num)
        res_data = band.ReadAsArray(start_col, start_row, cols_read, rows_read)
        return res_data
 
    @staticmethod
    def get_raster_band(raster_path):
        # 注册栅格驱动
        gdal.AllRegister()
        gdal.SetConfigOption('gdal_FILENAME_IS_UTF8', 'YES')
        # 打开输入图像
        dataset = gdal.Open(raster_path, gdal.GA_ReadOnly)
        if dataset == None:
            print('打开图像{0} 失败.\n', raster_path)
        raster_band = dataset.RasterCount
        return raster_band
 
    @staticmethod
    def get_file_size(raster_path):
        """获取栅格仿射变换参数"""
        # 注册栅格驱动
        gdal.AllRegister()
        gdal.SetConfigOption('gdal_FILENAME_IS_UTF8', 'YES')
 
        # 打开输入图像
        dataset = gdal.Open(raster_path, gdal.GA_ReadOnly)
        if dataset == None:
            print('打开图像{0} 失败.\n', raster_path)
        # 列
        raster_width = dataset.RasterXSize
        # 行
        raster_height = dataset.RasterYSize
        return raster_width, raster_height
 
    @staticmethod
    def get_file_geotransform(raster_path):
        """获取栅格仿射变换参数"""
        # 注册栅格驱动
        gdal.AllRegister()
        gdal.SetConfigOption('gdal_FILENAME_IS_UTF8', 'YES')
 
        # 打开输入图像
        dataset = gdal.Open(raster_path, gdal.GA_ReadOnly)
        if dataset == None:
            print('打开图像{0} 失败.\n', raster_path)
 
        # 获取输入图像仿射变换参数
        input_geotransform = dataset.GetGeoTransform()
        return input_geotransform
 
    @staticmethod
    def get_file_proj(raster_path):
        """获取栅格图像空间参考"""
        # 注册栅格驱动
        gdal.AllRegister()
        gdal.SetConfigOption('gdal_FILENAME_IS_UTF8', 'YES')
 
        # 打开输入图像
        dataset = gdal.Open(raster_path, gdal.GA_ReadOnly)
        if dataset == None:
            print('打开图像{0} 失败.\n', raster_path)
 
        # 获取输入图像空间参考
        input_project = dataset.GetProjection()
        return input_project
 
    @staticmethod
    def write_file(dataset, geotransform, project, output_path, out_format='GTiff', eType=gdal.GDT_Float32):
        """写入栅格"""
        if np.ndim(dataset) == 3:
            out_band, out_rows, out_cols = dataset.shape
        else:
            out_band = 1
            out_rows, out_cols = dataset.shape
 
        # 创建指定输出格式的驱动
        out_driver = gdal.GetDriverByName(out_format)
        if out_driver == None:
            print('格式%s 不支持Creat()方法.\n', out_format)
            return
 
        out_dataset = out_driver.Create(output_path, xsize=out_cols,
                                        ysize=out_rows, bands=out_band,
                                        eType=eType)
        # 设置输出图像的仿射参数
        out_dataset.SetGeoTransform(geotransform)
 
        # 设置输出图像的投影参数
        out_dataset.SetProjection(project)
 
        # 写出数据
        if out_band == 1:
            out_dataset.GetRasterBand(1).WriteArray(dataset)
        else:
            for i in range(out_band):
                out_dataset.GetRasterBand(i + 1).WriteArray(dataset[i])
        del out_dataset

定义计算NDVI的函数

def cal_ndvi(multi):
    '''
    计算高分NDVI
    :param multi:格式为列表,依次包含[遥感文件路径,开始行号,开始列号,待读的行数,待读的列数]
    :return: NDVI数组
    '''
    input_file, start_col, start_row, cols_step, rows_step = multi
    dataset = gdal.Open(input_file, gdal.GA_ReadOnly)
    nir_data = GdalUtil.read_block_data(dataset, 4, cols_step, rows_step, start_col=start_col, start_row=start_row)
    red_data = GdalUtil.read_block_data(dataset, 3, cols_step, rows_step, start_col=start_col, start_row=start_row)
    ndvi = (nir_data - red_data) / (nir_data + red_data)
    ndvi[(ndvi > 1.5) | (ndvi < -1)] = 0
    return ndvi
定义主函数
if __name__ == "__main__":
    input_file = r'D:\originalData\GF1\namucuo2021.tif'
    output_file = r'D:\originalData\GF1\namucuo2021_ndvi.tif'
    method = 'joblib'
    # method = 'multiprocessing'
    # 获取文件主要信息
    raster_cols, raster_rows = GdalUtil.get_file_size(input_file)
    geotransform = GdalUtil.get_file_geotransform(input_file)
    project = GdalUtil.get_file_proj(input_file)
    # 定义分块大小
    rows_block_size = 50
    cols_block_size = 50
    multi = []
    for j in range(0, raster_rows, rows_block_size):
        for i in range(0, raster_cols, cols_block_size):
            if j + rows_block_size < raster_rows:
                rows_step = rows_block_size
            else:
                rows_step = raster_rows - j
            # 数据横向步长
            if i + cols_block_size < raster_cols:
                cols_step = cols_block_size
            else:
                cols_step = raster_cols - i
            temp_multi = [input_file, i, j, cols_step, rows_step]
            multi.append(temp_multi)
 
    t1 = time.time()
    if method == 'multiprocessing':
        # multiprocessing方法
        pool = Pool(processes=cpu_count()-1)
        # 注意map函数中传入的参数应该是可迭代对象,如list;返回值为list
        res = pool.map(cal_ndvi, multi)
        pool.close()
        pool.join()
    else:
        # joblib方法
        res = Parallel(n_jobs=-1)(delayed(cal_ndvi)(input_list) for input_list in multi)
 
    t2 = time.time()
    print("Total time:" + (t2 - t1).__str__())
 
    # 将multiprocessing中的结果提取出来,放回对应的矩阵位置中
    out_data = np.zeros([raster_rows, raster_cols], dtype='float')
    for result, input_multi in zip(res, multi):
        start_col = input_multi[1]
        start_row = input_multi[2]
        cols_step = input_multi[3]
        rows_step = input_multi[4]
        out_data[start_row:start_row + rows_step, start_col:start_col + cols_step] = result
 
    GdalUtil.write_file(out_data, geotransform, project, output_file)

双重for循环时,两层for循环都使用multiprocessing时会报错,这时可以外层for循环使用joblib方法,内层for循环改为multiprocessing方法,不会报错

到此这篇关于python多线程方法详解的文章就介绍到这了,更多相关python多线程内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python中元组,列表,字典的区别
May 21 Python
Python3下错误AttributeError: ‘dict’ object has no attribute’iteritems‘的分析与解决
Jul 06 Python
python中hashlib模块用法示例
Oct 30 Python
Python入门之三角函数atan2()函数详解
Nov 08 Python
Python实现统计英文文章词频的方法分析
Jan 28 Python
Python opencv实现人眼/人脸识别以及实时打码处理
Apr 29 Python
详解pandas如何去掉、过滤数据集中的某些值或者某些行?
May 15 Python
使用django实现一个代码发布系统
Jul 18 Python
对tensorflow中的strides参数使用详解
Jan 04 Python
Python制作简易版小工具之计算天数的实现思路
Feb 13 Python
解决Python paramiko 模块远程执行ssh 命令 nohup 不生效的问题
Jul 14 Python
Python程序慢的重要原因
Sep 04 Python
用Python生成会跳舞的美女
基于Pygame实现简单的贪吃蛇游戏
Dec 06 #Python
Python可变集合和不可变集合的构造方法大全
Dec 06 #Python
Python实现视频中添加音频工具详解
Dec 06 #Python
Python实现GIF动图以及视频卡通化详解
Python实现照片卡通化
用Python爬取英雄联盟的皮肤详细示例
You might like
PHPMailer使用教程(PHPMailer发送邮件实例分析)
2012/12/06 PHP
基于PHP 面向对象之成员方法详解
2013/05/04 PHP
PHP实现采集中国天气网未来7天天气
2014/10/15 PHP
Javascript查询DBpedia小应用实例学习
2013/03/07 Javascript
在线一元二次方程计算器实例(方程计算器在线计算)
2013/12/22 Javascript
js验证IP及子网掩码的合法性有效性示例
2014/04/30 Javascript
浅谈javascript回调函数
2014/12/07 Javascript
Angularjs制作简单的路由功能demo
2015/04/14 Javascript
JavaScript中 ES6 generator数据类型详解
2016/08/11 Javascript
使用gulp搭建本地服务器并实现模拟ajax
2017/04/05 Javascript
微信小程序 setData使用方法及常用错误解决办法
2017/05/11 Javascript
js 监控iframe URL的变化实例代码
2017/07/12 Javascript
基于jquery trigger函数无法触发a标签的两种解决方法
2018/01/06 jQuery
vue-cli history模式实现tomcat部署报404的解决方式
2019/09/06 Javascript
使用vue-cli4.0快速搭建一个项目的方法步骤
2019/12/04 Javascript
JS写滑稽笑脸运动效果
2020/05/28 Javascript
python标准日志模块logging的使用方法
2013/11/01 Python
Python计算三维矢量幅度的方法
2015/06/15 Python
Python运算符重载详解及实例代码
2017/03/07 Python
Pandas 数据处理,数据清洗详解
2018/07/10 Python
python使用suds调用webservice接口的方法
2019/01/03 Python
Python Numpy 实现交换两行和两列的方法
2019/06/26 Python
python编写简单端口扫描器
2019/09/04 Python
python实现超市商品销售管理系统
2019/10/25 Python
Python3并发写文件与Python对比
2019/11/20 Python
python使用建议技巧分享(三)
2020/08/18 Python
如何利用CSS3制作3D效果文字具体实现样式
2013/05/02 HTML / CSS
中国包裹转运寄送国际服务:Famiboat
2019/07/24 全球购物
中西医结合临床医学专业大学生自荐信
2013/09/28 职场文书
节能环保演讲稿
2014/08/28 职场文书
党员个人剖析材料(四风问题)
2014/10/07 职场文书
寒暑假实习证明书模板
2014/11/29 职场文书
在职证明格式样本
2015/06/15 职场文书
读书笔记怎么写
2015/07/01 职场文书
人身损害赔偿协议书
2016/03/22 职场文书
导游词之西安大清真寺
2019/12/17 职场文书