python 多进程分析

来源:互联网 发布:淘宝代销不赚钱 编辑:程序博客网 时间:2024/06/17 13:49

一,背景

最近工作中需要使用python脚本将一个xlsx文件中的数据全部导入到es中,由于文件中的内容丰富,数量又多。直接通过python文件读入之后在写入es中,时间比较长,总共接近两万条数据从执行程序,到最终入到es完成,差不多要花10分钟。

通过使用多进程的方式,极大地提高了数据导入es的性能。在这里记录一下对python多进程程序进行的一些分析,研究。

二,性能消耗在哪些地方

为了优化导入速度需要找到花费时间较长的地方在哪。一般来说,一个任务执行时间较长会在两个地方。1.进行复杂的计算。2.执行IO操作中存在阻塞,长时间等待IO。

三,程序功能说明

该程序有几个部分,首先是使用openpyxl读xlsx文件中的数据,然后放到一个list中。其次,构造es的数据格式,导入数据到es中。由此可以看出来,在这个程序中既包含了复杂计算比如向list中插入数据,又包含IO操作,所以,在这两个部分都存在耗费时间的问题,这就需要具体问题具体分析。


四,实验环境

测试环境一:
系统:单核,单CPU
数据量:2000
操作:读取xlsx,并发送到es中

首先在单核单CPU,单进程情况下:

main 361 ...Sat Nov 11 04:32:49 2017main 363...Sat Nov 11 04:33:07 2017---------------耗时为18s

其次在单核单CPU,多进程情况下:

main 361 ...Sat Nov 11 04:34:47 2017main 363...Sat Nov 11 04:35:08 2017---------------耗时为19s,反而耗时高了

测试环境二:
系统:2核,2CPU
数据量:2000条

2核2CPU的,单进程:

main 361 ...Sat Nov 11 04:40:15 2017main 363...Sat Nov 11 04:40:33 2017---------------耗时18s

2核2CPU,4个进程:

main 361 ...Sat Nov 11 04:41:46 2017main 363...Sat Nov 11 04:41:59 2017---------------耗时为13s

测试环境三:
系统:2核,2CPU
数据量:4000条

2核2CPU的,单进程:

main 361 ...Sat Nov 11 05:30:22 2017main 363...Sat Nov 11 05:30:52 2017---------------耗时30s

2核2CPU,4个进程:

main 361 ...Sat Nov 11 05:29:08 2017main 363...Sat Nov 11 05:29:28 2017---------------耗时20s

五,总结分析

id 核心 数据量 进程 耗时 1 单核 2000 单进程 18s 2 单核 2000 4进程 19s 3 4核 2000 单进程 18s 4 4核 2000 4进程 13s 5 4核 4000 单进程 30s 6 4核 4000 4进程 20s

1和2对比

结论:
1. 多进程并没有提高程序的性能,反而造成了一定的性能下降。
2. 有些情况多进程并不能提高程序的性能

产生原因:
1. 由于系统为单核系统,所以每次程序运行的时候只有一个进程在使用CPU。
2. 由于该程序并没有长时间IO阻塞的情况,只存在复杂的计算。所以时间都耗费在CPU进行复杂计算上。
3. 由于多进程存在进程间的切换,会消耗一定的时间,所以导致耗时反而比单进程时间还长。


1和3对比

结论
1. 多核对于单进程来说没有任何性能上的提升

产生的原因:
1. 多核单进程,实际上每次只有一个进程在使用CPU。


2和4对比

结论:
1. 多核可以明显提升程序的性能。

产生原因:
1. 每个cpu可以并行的执行程序,不像单核CPU那样是交替并发的执行。


5和6对比

结论
1. 数据量越大多核性能优势体现的越明显。

产生的原因:
1. 理想情况应该是多一个核,性能提升翻一倍,但是由于存在一些进程间的切换,所以没法达到理想情况。数据量越大消耗的时间越多,性能翻倍之后,消耗时间也会翻倍的减少,所以数量越大效果越明显。


六,附上程序源码

#coding=utf-8  from datetime import datetime  import threadingfrom elasticsearch import Elasticsearch  from elasticsearch import helpers  from openpyxl import load_workbookimport sysimport timefrom multiprocessing import Processreload(sys)sys.setdefaultencoding('utf-8') def insertApplication(content):    es = Elasticsearch(hosts=["xx.xx.xx.xx:9200"], timeout=5000)      actions = []      i=1      index = 0    #print "start generate index..."    for line in content:        try:            action={                  "_index":"my_test_v1",                  "_type":"office",                  "_id":i,                  "_source":{                          u"id":unicode(line[0]),                          u"proto":unicode(line[1]).decode('utf8'),                          u"sip":unicode(line[2]).decode('utf8'),                          u"sport":unicode(line[3]).decode('utf8'),                          u"dip":unicode(line[4]).decode('utf8'),                          u"dport":unicode(line[5]).decode('utf8'),                          u"status":unicode(line[6]),                        }                  }          except:            print "======="            print line            print "+++++++"        i+=1          actions.append(action)         if(len(actions)==500):            success, _ = helpers.bulk(es, actions, raise_on_error=True)            actions = []            #del actions[0:len(actions)]       if (len(actions) > 0):          helpers.bulk(es, actions, raise_on_error=True)def readFile():    wb = load_workbook(filename=r'~/myfile.xlsx')    sheets = wb.get_sheet_names()   # 获取所有表格(worksheet)的名字    sheet0 = sheets[0]  # 第一个表格的名称    ws = wb.get_sheet_by_name(sheet0) # 获取特定的 worksheet    # 获取表格所有行和列,两者都是可迭代的    rows = ws.rows    columns = ws.columns    return rowsdef sendToEs(rows, start, end):    content = []    for row in rows[start:end]:        line = [col.value for col in row]        content.append(line)    insertApplication(content)def task():    rows = readFile()    process_list = []    count = 1000    for i in range(0,4):        process_list.append(Process(target=sendToEs, args=(rows,i*count,(i+1)*count - 1)))    return process_listdef multiRun():    process_list = task()    for process in process_list:        process.start()    # 主进程中等待所有子进程退出    for process in process_list:        process.join()def run():    rows = readFile()    count = 1000    for i in range(0,4):        sendToEs(rows,i*count,(i+1)*count - 1)if __name__=='__main__':    print "main 361 ..." + time.ctime()    #单进程执行    run()    #多进程执行    multiRun()    print "main 363..." + time.ctime()
原创粉丝点击