程序设计十:多进程文本分析

程序设计十:进程和线程

在这里插入图片描述

一、Map进程

定义map函数,对文本进行分词,并计算批量文本的词频统计结果,其中调用_statword函数来统计每个词语的词频,代码如下:

def map(queue, content_i):
    # 计算批量词频统计的结果
    print('map {} start...'.format(os.getpid()))
    all_words = []
    for text in content_i:
        words = jieba.lcut(text)
        all_words.extend(words)
    word_freq_i = _statword(all_words)
    queue.put(word_freq_i)
    queue.join()

def _statword(all_words):
    '''
    统计词频
    :param all_words: 列表类型,包含分词
    :return: 字典类型,值为非停用词的词频
    '''
    freq = {}
    # freq = collections.defaultdict(default_value())    # 若下文不用 .get(word,0) 方法,则可以用此句初始化字典
    # 载入停用词
    stopwords = [line.strip() for line in open('stopwords_list.txt', 'r', encoding='utf-8').readlines()]
    # 统计词频
    for word in all_words:
        if word not in stopwords and word != ' ':
            freq[word] = freq.get(word, 0) + 1
    return freq

二、Reduce进程

定义reduce函数,根据队列获取的批量统计,更新全局词频统计,其中_update函数更新全局词频统计,代码如下:

def reduce(queue, word_freq):
    # 根据队列获取的批量统计,更新全局词频统计
    word_freq_i = queue.get()
    if word_freq_i == None:
        print('No word, {} end'.format(os.getpid()))
    else:
        word_freq = _update(word_freq, word_freq_i)
        print('reduce {} start...'.format(os.getpid()))
        queue.task_done()

def _update(word_freq, word_freq_i):
    for key in word_freq_i.keys():
        if key in word_freq.keys():
            word_freq[key] += word_freq_i[key]
        else:
            word_freq[key] = word_freq_i[key]
    return word_freq

三、进程建立与启动

if __name__ == '__main__':中,建立Map进程和Reduce进程,将文本切片分给各个Map进程,再由Map进程统计后,添加到队列中,Reduce进程从队列中获取统计结果,并更新全局结果

# 以下代码均在 if __name__ == '__main__': 中
for i in range(proc_num):
            # 根据文本量,判断每个进程需要读入多少文本
            content_i = content[
                        i * LEN // proc_num:(i + 1) * LEN //proc_num].copy()  
            print('----建立第{}/{}个进程----'.format(i+1,proc_num))
            #print(f'要处理的文本如下\n{content_i[:3]}')
            Map = Process(target=map, args=(queue, content_i,))   # 统计批量词频
            map_lis.append(Map)  # 记录批量词频的结果
        for j in range(proc_num):
            Reduce = Process(target=reduce, args=(queue, word_freq,))  # 更新词频
            Reduce.daemon=True
            reduce_lis.append(Reduce)  # 记录更新后总词频
        #print('------ start map ------')
        for Map in map_lis:
            Map.start()
        #print('---start reduce---')
        for Reduce in reduce_lis:
            Reduce.start()
        for Map in map_lis:
            Map.join()
        for Map in map_lis:
            queue.put(None)
        for Reduce in reduce_lis:
            Reduce.join()

四、运行结果与不同进程数运行时间比较

测试进程数在[1,10]之间的运行时间,结果如下:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

绘制图像可得到如下结果(运行三次):

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

可以观察到如下结论:

  1. 在本次测试范围内,随着进程数量的增加,总运行时间呈现下降趋势,这是因为进程数增加增多个进程并行,会加快执行效率,减少用时;
  2. 在本次测试范围内,随着进程数的增多,运行时间的减小趋势越来越小,边际效用递减,这是因为建立进程也会耗时,以及除并行部分外还有其他消耗资源的因素,导致边际递减
  3. 运行时长并不一直下降,而是略有起伏
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值