jkshen8 2023-11-15 10:14 采纳率: 50%
浏览 24

Python中threading和xlwings结合使用报错,pywintypes.com_error: (-2147221008, '尚未调用 CoInitialize。', None, None)

背景:利用xlwings库读取EXCEL文件,逐个获取sheet名和sheet数据,对应组成字典返回;当Excel内sheet较多并且数据量较大时,返回字典效率太低,现思考通过多线程同时获取sheet数据.
问题:当加入threading多线程时代码报错,error:pywintypes.com_error: (-2147221008, '尚未调用 CoInitialize。', None, None)

img

Python代码如下:

import time
import pandas as pd
import os
import xlwings as xw
import threading

def read_sht(sht):
    if sht.range('a1').value:
        print('Sheet名:', sht.name)
        last_cell = sht.used_range.last_cell
        last_row = last_cell.row
        last_col = last_cell.column
        header = sht.range((1, 1), (1, last_col)).value

        if sht.range('a3').value:
            data = sht.range((2, 1), (last_row, last_col)).value
        else:
            data = [sht.range((2, 1), (last_row, last_col)).value]

        df = pd.DataFrame(data, columns=header)
    return df

def multi_read_sht(path):
    thread_list = []
    dic = {}
    with xw.App(visible=False, add_book=False) as app:
        for root, dirs, files in os.walk(path):
            for file in files:
                excel = os.path.join(root, file)
                if excel.endswith(('.xls', '.xlsx')):
                    print('\n%s 正在打开 %s 读取Sheet名和数据......' % (time.strftime('%Y-%m-%d %H:%M:%S'), file))
                    wb = app.books.open(excel)
                    for sht in wb.sheets:
                        t = threading.Thread(target=lambda x : dic.update({sht.name:read_sht(x)}),args=(sht,))
                        t.start()
                        thread_list.append(t)

                    for thread in thread_list:
                        thread.join()
    return dic

if __name__ == "__main__":
    path = os.getcwd()
    multi_read_sht(path)
  • 写回答

1条回答 默认 最新

  • 木头人123。 2023-11-16 13:49
    关注

    你的问题出在尝试在多线程环境中使用 COM 对象(例如 xlwings 库使用的 Excel 对象)。COM 对象并不是线程安全的,因此在多线程中使用 COM 对象可能会导致问题。

    你可以尝试使用多进程代替多线程来解决这个问题。Python 的 multiprocessing 库可以很容易地实现这一点。以下是一个例子:

    import multiprocessing
    
    def read_sht(sht_name, excel, dic):
        with xw.App(visible=False, add_book=False) as app:
            wb = app.books.open(excel)
            sht = wb.sheets[sht_name]
            dic[sht_name] = process_sht(sht)
    
    def multi_read_sht(path):
        manager = multiprocessing.Manager()
        dic = manager.dict()
        jobs = []
        for root, dirs, files in os.walk(path):
            for file in files:
                excel = os.path.join(root, file)
                if excel.endswith(('.xls', '.xlsx')):
                    print('\n%s 正在打开 %s 读取Sheet名和数据......' % (time.strftime('%Y-%m-%d %H:%M:%S'), file))
                    with xw.App(visible=False, add_book=False) as app:
                        wb = app.books.open(excel)
                        for sht in wb.sheets:
                            p = multiprocessing.Process(target=read_sht, args=(sht.name, excel, dic))
                            jobs.append(p)
                            p.start()
    
        for proc in jobs:
            proc.join()
    
        return dict(dic)
    

    注意,上述代码的工作方式是对每个进程都打开一个独立的 Excel 应用程序实例,并读取一个单独的工作表。这是因为 COM 对象不能跨进程共享。因此,这可能会导致大量的 Excel 进程被打开,这可能会消耗大量的系统资源。

    另外,由于进程间通信比线程间通信更复杂,所以我们需要使用 multiprocessing.Manager 来创建一个可以在多个进程之间共享的字典。

    评论

报告相同问题?

问题事件

  • 创建了问题 11月15日

悬赏问题

  • ¥15 基于卷积神经网络的声纹识别
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 CSAPPattacklab
  • ¥15 一直显示正在等待HID—ISP
  • ¥15 Python turtle 画图
  • ¥15 stm32开发clion时遇到的编译问题