python多线程生成excel一些感悟吧...
最近,做了很多个报表,一开始并没有考虑到效率的问题,只是实现了excel的导出,后来慢慢做出现好多问题。 1、每一个excel 的sheet很多,大概四五十个,跑完一个excel得花四十多分钟,甚至一个小时。。。有时候甚至线程直接卡死了不动了。可能是io的交互太长了,也不知道撒原因。 2、每一类型的excel至少也得需要出30多个吧,考虑到进程池用多进程去跑,但是发现多进程消耗太大,机器也就4核的,我至少也得开十个进程,机器扛不住,可能也还是IO的交互时间长,进程也会卡死,所以放弃了。 3、为了解决进程池的开销太大,和进程卡死的问题,我改成了线程池,每一个类型的excel开启十个线程去跑,但是python的线程由于GIL全局锁的原因,实际上每次还是一个线程再跑,而且对每一个excel来说,很多个sheet需要生成,同一个线程中IO交互也非常频繁,而且还是会存在线程卡死的情况,效率也不行。 4、为了解决进程池的开销问题,和线程池中的io交互过长,会导致线程卡死,IO交互的时候线程会暂停等待IO交互而白白浪费时间。最终,goole、百度,python的协程,简直是神器,IO交互的时候,线程不会等待,而是会执行其他的协程。 5、因为我的是flask应用,需要向其他应用提供生成excel的接口,最终我的解决方案是,在每一个web请求中,创建进程池异步调用,并创建线程池(为了跑多个excel),每个线程开启多个协程任务(生成每个excel中的sheet)。大大提高了excel的生成效率,而且,线程也没与出现卡死的情况。下面是,threadpool 和 协程的基本使用:
1、每一个线程里面会有多个协程对象。 2、协程的运行是由顺序的,只是在IO交互的时候,不用等待IO交互完成。 3、多线程中使用协程的时候必须新建loop对象。
import threadpool import asyncio import time async def do_work_one(name): """ 定义一个协程对象 :return: """ time.sleep(4) print(name, do_work_one) async def do_work_two(name): """ 定义一个协程对象 :return: """ time.sleep(2) print(name, do_work_two) def task_do_work(name): """ 1、每一个线程里面会有多个协程对象 2、协程的运行是由顺序的,只是在IO交互的时候,不用等待IO交互完成 3、多线程中使用协程的时候必须新建loop对象 :return: """ loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) coroutine1 = do_work_one(name) coroutine2 = do_work_two(name) tasks = [asyncio.ensure_future(coroutine1), asyncio.ensure_future(coroutine2)] loop.run_until_complete(asyncio.wait(tasks)) return success def call_back(param, result): print(回调, param, result) if __name__ == __main__: jobs = [] pool = threadpool.ThreadPool(2) work_requests = [] for i in range(2): work_requests.append(threadpool.WorkRequest(task_do_work, args=(线程-{0}.format(i), ), callback=call_back, exc_callback=call_back)) [pool.putRequest(req) for req in work_requests] pool.wait() print(end)
下一篇:
python中文画图显示乱码解决办法