如何在OpenPYXL对象中使用多进程? [英] How to use multiprocess in openpyxl object?

查看:17
本文介绍了如何在OpenPYXL对象中使用多进程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要处理一个有很多工作表的EXCEL,但每个工作表都有很大的数据量,如果使用Openpyxl来加载这个EXCEL,会花费很多时间,所以我想对每个工作表进行多进程分析。

简短代码如下:

import multiprocessing as mp
import openpyxl
def LoadEx():
        wb=openpyxl.load_workbook('example.xlsx')
        sheetnames=wb.get_sheet_names()
        return sheetnames, wb

def job(sheet,wb):
    gs=wb.get_sheet_by_name(sheet)
    for i in range(10):
        if gs.cell(row=i,column=2).value=='Target':
            gs.cell(row=i,column=3).value='OK'

if __name__=='__main__':
    sheetnames,wb=LoadEx()
    pool=mp.Pool()
    for sheetname in sheetnames:
        res=pool.apply_async(job, (sheetname,wb))
    pool.close()
    pool.join()
    wb.save('example_output.xlsx')
但是,文件‘Example_output.xlsx’似乎没有保存作业()的结果, 在这种情况下,如何获得多进程的效果? 希望有人能帮我,想

推荐答案

您可以使用multiprocessing操作,但您必须付费

  1. global wb成为您使用的每个process副本。 因此,使用4processes时,您的内存必须足够容纳4份工作簿。

  2. 由于wb是副本,您的更改属于此副本。 您必须将更改复制到一个工作簿中。 复制工作表可能很耗时。

为了克服酸洗错误,我将排队从ws改为wsDiff。 不是写入ws副本,而是汇总对wsDiff的更改。 另外,复制到目标wb会更快。

时间表:cpucount=2,10个工作表,工作量:def ws_job(...

Job Processes   without mp           2               4  
Time          0:00:21.260746  0:00:10.214942  0:00:07.097369  
此工作示例适用于给定的问题def job。 ,例如:

import multiprocessing as mp
import queue, os, time
import random as rd
import openpyxl


class wsDiff(object):
    def __init__(self, row, column, value):
        self.row = row
        self.column = column
        self.value = value


def ws_job(wb, ws_idx):
    ws = wb.worksheets[ws_idx]
    print('pid %s: process (%s)' % (os.getpid(), ws.title))

    # *** DO SOME STUFF HERE***
    # Simulate workload
    time.sleep(rd.randrange(1, 4))

    diff = []
    for i in range(1, 11):
        if ws.cell(row=i, column=2).value == 'Target':
            #ws.cell(row=i, column=3).value = 'OK'
            diff.append( wsDiff(i, 3, 'OK') )

    return diff


def job(fq, q, wb):
    while True:
        try:
            ws_idx = fq.get_nowait()
        except queue.Empty:
            print('pid %s: exit job' % os.getpid())
            exit(0)

        q.put((ws_job(wb, ws_idx), ws_idx))
        time.sleep(0.1)


def writer(q, wb):
    print('start writer_handler')
    while True:
        try:
            diff, i_ws = q.get()
        except ValueError:
            print('writer ValueError exit(1)')
            exit(1)

        if diff == None:
            wb.save('../test/example_output.xlsx')
            exit(0)

        ws = wb.worksheets[i_ws]
        print('pid %s: update sheet %s from diff' % (os.getpid(), ws.title))
        for d in diff:
            ws.cell(row=d.row, column=d.column).value = d.value


def mpRun():
    wb = openpyxl.load_workbook('../test/example.xlsx')

    f_q = mp.Queue()
    for i in range(len(wb.worksheets)):
        f_q.put(i)

    w_q = mp.Queue()
    w_p = mp.Process(target=writer, args=(w_q, wb))
    w_p.start()
    time.sleep(0.1)

    pool = [mp.Process(target=job, args=(f_q, w_q, wb)) for p in range(os.cpu_count() + 2)]
    for p in pool:
        p.start()
        time.sleep(0.1)

    for p in pool:
        p.join()

    time.sleep(0.2)
    # Terminate Process w_p after all Sheets done
    w_q.put((None, None))
    w_p.join()

    print('EXIT __main__')

使用Python测试:3.4.2-Openpyxl:2.4.1-LibreOffice:4.3.3.2

这篇关于如何在OpenPYXL对象中使用多进程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆