2017-04-11 18 views
1

私はそれに多くのシートを持つExcelに対処する必要がありますが、すべてのシートは大きなデータを持っています。このExcelを読み込むためにopenpyxlを使用すると、時間がかかるので、各シートをマルチプロセスで分析します。openpyxlオブジェクトでマルチプロセスを使用するには?

このような簡単なコード:

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」(仕事を保存しないように見える)の結果、 はどのように私はこのケースでは、マルチの効果を得るために行う必要があります? 誰かが私を助けてくれるかもしれないと思います

答えて

1

multiprocessingを使用するとできますが、にはを支払う必要があります。

  1. global wbは、使用するすべてのprocessためコピーなります。 を使用すると、メモリは、ワークブックのコピーを4枚保持するのに十分な大きさでなければなりません。

  2. wbがコピーであるとすれば、変更はこのコピーに属します。 変更をワークブックにコピーする必要があります。 ワークシートのコピーに時間がかかることがあります。酸洗エラーを克服するために

は、私がwsDiffからwsをキューイングやってから変更しました。 wsコピーに書き込む代わりに、aggreateがwsDiffに変更されます。 ボーナスとして、wbにコピーする方が高速になります。

Time table: cpu_count=2, 10 Worksheets, workload: 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__') 

:3.4.2 - openpyxl:2.4.1 - LibreOfficeの:4.3.3.2

+0

stovflの返答をありがとう、これは私に多くの助けてください。 しかし、コードを実行しようとすると、それが表示されます TypeError:__init __()が見つかりませんでした1位置の引数が必要です: 'ワークシート'、無限ループで、終了できません、どうすれば修正できますか? – Jcwork

+1

WOW!それは今働く、あなたは本当に素晴らしいです。ありがとうございました! – Jcwork

0

残念ながら、ワークブックは共有状態が多いので、マルチプロセッシングには適していません。

+0

それを取得し、私は他の方法を試します、あなたに感謝助けて! – Jcwork

関連する問題