免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2824 | 回复: 4
打印 上一主题 下一主题

python 多线程效率问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2016-01-20 13:10 |只看该作者 |倒序浏览
我处理日志用python 多线程,碰到的问题如下
单个文件 2G,单线程,读取后处理,写入另一个文件后 200MB,用时:20s
5个文件 10G,多线程,读取后处理,写入5个文件(同样也是每个文件200MB左右),用时大概2分钟

给我的感觉像是串行,和我预期(5个文件处理20s)相差太大,请问这是怎么回事?

#!/usr/bin/python
# encoding=gb18030

import sys
import re
import os

reload(sys)
sys.setdefaultencoding('gb18030')
import codecs
import threading
import logging
import time
allFileNum = 0

logger = logging.getLogger("myLogger")
logger.setLevel(logging.DEBUG)
fh = logging.FileHandler('extact.log')
fh.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)

formater = logging.Formatter('%(asctime)s - %(message)s')
fh.setFormatter(formater)
ch.setFormatter(formater)

logger.addHandler(fh)
logger.addHandler(ch)


class myThread(threading.Thread):
    def __init__(self, threading_sum, file_path, target_city, target_dir):
        threading.Thread.__init__(self)
        self.threading_sum = threading_sum
        self.target_city = target_city
        self.file_path = file_path
        self.target_dir = target_dir

    def run(self):
        with self.threading_sum:
            logger.info("%s Starting!" % self.file_path)
            time.sleep(1)
            target_data(self.target_dir, self.file_path, self.target_city)
            logger.info("%s Exiting!" % self.file_path)


def get_files(path):
    global allFileNum
    '''
    打印一个目录下的所有文件夹和文件
    '''
    # 所有文件夹,第一个字段是次目录的级别
    dirList = []
    # 所有文件
    fileList = []
    # 返回一个列表,其中包含在目录条目的名称(google翻译)
    files = os.listdir(path)
    for f in files:
        if (os.path.isdir(path + '/' + f)):
            # 排除隐藏文件夹。因为隐藏文件夹过多
            if (f[0] == '.'):
                pass
            else:
                # 添加非隐藏文件夹
                dirList.append(f)
        if (os.path.isfile(path + '/' + f)):
            # 添加文件
            fileList.append(f)
    # 当一个标志使用,文件夹列表第一个级别不打印
    i_dl = 0
    for dl in dirList:
        if (i_dl == 0):
            i_dl = i_dl + 1
    return fileList
    for fl in fileList:
        # 打印文件
        print '-' * (int(dirList[0])), fl
        # 随便计算一下有多少个文件
        allFileNum = allFileNum + 1


def extract(path, target_city):
    target_dir = path + target_city

    if os.path.isdir(target_dir):
        pass
    else:
        os.makedirs(target_dir)

    fileList = get_files(path)
    # 设置线程数
    threading_sum = threading.Semaphore(5)
    for file in fileList:

        filePath = path + file
        if not os.path.isfile(filePath):
            logger.error("the path is not file")
            continue

        thread = myThread(threading_sum, filePath, target_city, target_dir)
        thread.start()
        logger.info("All thread has create,Wait for all thread exit.")

    # 等待所有线程结束
    for t in threading.enumerate():
        if t is threading.currentThread():
            continue
        t.join()
        logger.info("All thread exit")




def target_data(target_dir, file_path, target_city):
    logger.info(target_dir)
    target_file_path = target_dir + "//" + os.path.basename(file_path) + "_" + target_city
    regex = re.compile(r'service.*what=.*city=(.*)')
    file = codecs.open(file_path, 'r', 'gb18030')
    searchWordfile = codecs.open(target_file_path, 'w', 'gb18030')
    while 1:
        lines = file.readlines(100000)
        if len(lines) < 1:
            break
        for line in lines:
            searchObj = regex.search(line)
            if searchObj:
                city = searchObj.group(1)
                if target_city in city:
                    searchWordfile.write(line)


def main():
    # if len(sys.argv) < 2:
    #     print 'No action specified.'
    #     sys.exit()
    # extract(path=sys.argv[1], target_city=sys.argv[2])
    extract(path="D://log1//", target_city="北京")

    logger.info("extract finished")
    sys.exit()


if __name__ == '__main__':
    main()

论坛徽章:
2
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:57:09
2 [报告]
发表于 2016-01-21 15:44 |只看该作者
python的多线程其实是单线程的,有一个全局锁
只能使用一个核

python多线程没有效率,python的多线程基本上都是用来避免阻塞的而非性能应用
对性能有需求请使用多进程

论坛徽章:
0
3 [报告]
发表于 2016-01-25 15:26 |只看该作者
同意楼上

如果纯粹的磁盘IO操作,同时打开过多的文件反而会影响性能(这和语言无关)

论坛徽章:
11
2015年迎新春徽章
日期:2015-03-04 09:55:282017金鸡报晓
日期:2017-02-08 10:39:4215-16赛季CBA联赛之辽宁
日期:2016-12-15 10:24:1715-16赛季CBA联赛之佛山
日期:2016-11-30 09:04:2015-16赛季CBA联赛之江苏
日期:2016-04-29 15:56:1215-16赛季CBA联赛之同曦
日期:2016-04-12 13:21:182016猴年福章徽章
日期:2016-02-18 15:30:3415-16赛季CBA联赛之山东
日期:2016-02-16 11:37:52每日论坛发贴之星
日期:2016-02-07 06:20:00程序设计版块每日发帖之星
日期:2016-02-07 06:20:0015-16赛季CBA联赛之新疆
日期:2018-01-09 16:25:37
4 [报告]
发表于 2016-02-04 16:11 |只看该作者
在386时代(单CPU,单核的,当时还没有一个CPU有多个核的说法)
就发现多线程还没有单线程吞吐量高

如果你的磁盘IO也是"386级别"的.就正常了

论坛徽章:
6
程序设计版块每日发帖之星
日期:2016-01-15 06:20:00操作系统版块每日发帖之星
日期:2016-01-16 06:20:00IT运维版块每日发帖之星
日期:2016-02-04 06:20:00数据库技术版块每日发帖之星
日期:2016-02-04 06:20:00程序设计版块每日发帖之星
日期:2016-02-10 06:20:01每日论坛发贴之星
日期:2016-02-10 06:20:01
5 [报告]
发表于 2016-02-07 18:39 |只看该作者
试试多进程来处理,特别是多进程pool,简单又方便
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP