3

我正在尝试处理python中的多线程。我有工作代码计算字数、文本行数,并创建一个包含每个字数的字典。它在代码注释中提到的小文件上运行得很快。但是我通常使用 glob 来拉入多个文件。当我这样做时,我的运行时间显着增加。同时,由于我的脚本是单线程的,我看到我有 3 个其他内核处于空闲状态,而其中一个已达到最大值。

我想我会给 pythons 多线程模块一个镜头,这是我到目前为止所做的(非工作):

#!/bin/python
#
# test file: http://www.gutenberg.org/ebooks/2852.txt.utf-8

import fileinput
from collections import defaultdict
import threading
import time

inputfilename = 'pg2852.txt'

exitFlag = 0

line = []
line_counter = 0
tot_words = 0
word_dict = defaultdict(int)

def myCounters( threadName, delay):
        for line in fileinput.input([inputfilename]):
                line = line.strip();
                if not line: continue
                words = line.split()
                tot_words += len(words)
                line_counter += 1
                for word in words:
                        word_dict[word] += 1

        print "%s: %s:" %( threadName, time.ctime(time.time()) )
        print word_dict
        print "Total Words: ", tot_words
        print "Total Lines: ", line_counter

try:
        thread.start_new_thread( myCounters, ("Thread-1", 2, ) )
        thread.start_new_thread( myCounters, ("Thread-2", 4, ) )
except:
        print "Error: Thread Not Started"

while 1:
        pass

对于那些尝试此代码的人,它不起作用。我假设我需要将输入文件分成块并以某种方式合并输出。? 映射/减少?也许有一个更简单的解决方案?

编辑:

也许是这样的:

  1. 打开文件,
  2. 把它分成几块
  3. 将每个块提供给不同的线程
  4. 获取计数并在每个块上构建 dict
  5. 合并计数/字典
  6. 返回结果
4

1 回答 1

5

首先,您需要使用并行进程而不是并行线程是正确的。由于全局解释器锁 (GIL),执行此类任务 [参见下面的ETA] 将无法很好地扩展到 python 下的多个线程。

如果您想并行处理单个文件,显而易见的方法是首先检查文件大小,然后将相同大小的块分配给多个进程。这只涉及告诉每个进程从文件中的哪个位置开始,以及从哪个位置结束。(当然,您必须小心不要将任何单词或行数两次。一种简单的方法是让每个进程忽略初始字节,直到它到达行首,然后开始计数)。

但是,您在问题中声明您将使用 glob 来处理多个文件。因此,与其采用复杂的文件分块并将块分配给不同的进程,一个更简单的选择是将不同的文件分配给不同的进程。


预计到达时间:

在 Python 中使用线程适用于某些用例,例如使用长时间阻塞的 I/O 函数。@uselpa 是对的,如果处理受 I/O 限制,那么线程可能会执行良好,但这里的情况并非如此,因为瓶颈实际上是解析,而不是文件 I/O。这是由于 Python 作为解释型语言的性能特点;在编译语言中,I/O 更有可能成为瓶颈。

我提出这些声明是因为我刚刚根据原始代码进行了一些测量(使用包含 100 个 pg2852.txt 连接副本的测试文件):

  • 作为单线程运行大约需要 2.6 秒来读取和解析文件,但当我注释掉解析代码时只需要 0.2 秒。
  • 并行运行两个线程(从同一个文件中读取)耗时 7.2 秒,但并行启动的两个单线程进程仅耗时 3.3 秒即可完成。
于 2012-06-03T10:57:55.807 回答