Python多处理依赖于繁重的多线程情况

时间:2015-10-24 10:38:35

标签: python regex hang python-multithreading python-multiprocessing

我正在努力解决一个非常奇怪的Python行为,我无法摆脱它。

我创建了一个Python外部库,我从我的主python脚本中导入。该库接收一个巨大的(最多50MB)JSON文本文档,分为几个部分。我需要解析这些部分中的每一部分并使用正则表达式提取数据。

为了加快这个过程,并了解Python不能在多核CPU上扩展的限制,我决定使用多处理库来创建与物理CPU上可用核心一样多的进程。

库将主JSON拆分为多个部分,并初始化不同的multiprocessing.Process实例,将特定文本部分传递给每个进程。

我是这样做的:

p_one = multiprocessing.Process(
                name=name,
                target=functionOne,
                args=(buffer1, id1)
            )
p_one.start()

p_two = multiprocessing.Process(
                name=name,
                target=functionTwo,
                args=(buffer2, id2)
            )
p_two start()

p_three = multiprocessing.Process(
                name=name,
                target=functionThree,
                args=(buffer3, id3)
            )
p_three.start()    

p_four = multiprocessing.Process(
                name=name,
                target=functionFour,
                args=(buffer4, id4)
            )
p_four.start()


p_one.join()
p_two.join()
p_three.join()
p_four.join()

这通常有效,但是有时候其中一个被调用的连接会挂起并挂起整个主lib - 从而阻止我的主脚本继续运行。

子进程没有崩溃,他们使用Google re2作为正则表达式库,他们完成了解析程序。

如前所述,每次都不会发生这种情况,我会说这是非常随机的。如果我杀死整个进程并使用相同的字符串缓冲区重新启动它,那么它完全有效,所以正则表达式规则没有错,也没有挂任何东西。

我尝试使用多处理映射函数,但它最终创建了僵尸进程,因此我交换到了multiprocessing.Process。

我还检查了Pyrasite,并且阻塞的线程在连接函数上挂起。

"/usr/local/lib/python2.7/dist-packages/xxxxx/dispatcher.py", line 401, in p_domain
    p_two.join()
  File "/usr/lib/python2.7/multiprocessing/process.py", line 145, in join
    res = self._popen.wait(timeout)
  File "/usr/lib/python2.7/multiprocessing/forking.py", line 154, in wait
    return self.poll(0)
  File "/usr/lib/python2.7/multiprocessing/forking.py", line 135, in poll
    pid, sts = os.waitpid(self.pid, flag)

请您有任何提示/建议/某些内容可以帮助我理解为什么会发生这种情况以及如何解决这个问题?

非常感谢!

*加法*

这是在subprocess.Process()子项

中调用的一段代码的示例
def check_domains(buf, id):
    warnings = []
    related_list = []


    strings, _ = parse_json_string(buf)

    for string in strings:
        _current_result = _check_single_domain(string)

        # If no result, add a warning message
        if _current_result is False:
            warnings.append("String timed out in DOMAIN section.")
        else:
            if _current_result is not None:
                related_list.append(_current_result)

    related_list = list(set(related_list))

    [...cut...]



def _check_single_domain(string):

    global DOMAIN_RESULT

    # Check string length
    if len(string) > MAX_STRING_LENGTH_FOR_DOMAIN:
        return None

    # Check unacceptable characters inside string
    for unacceptable in UNACCEPTABLE_DOMAIN_CHARACTERS:
        if unacceptable in string:
            return None

    # Check if string contains unacceptable characters
    for required in REQUIRED_DOMAIN_CHARACTERS:
        if required not in string:
            return None

    # Try to match string against Domain regex using Thread with timeout
    thread = threading.Thread(name='Thread-DOMAIN', target=_perform_regex_against_string, args=(string, ))
    thread.setDaemon(True)
    thread.start()
    thread.join(TIMEOUT_REGEX_FOR_DOMAIN_IN_SECONDS)

    # If a time out occurred, return False that meaning no result got
    if thread.isAlive():
        return False

    if DOMAIN_RESULT is None:
        return None

    # Domain can not starts or ends with a dot character
    if DOMAIN_RESULT.endswith(".") or DOMAIN_RESULT.startswith("."):
        return None

    return DOMAIN_RESULT


def _perform_regex_against_string(string):

    global DOMAIN_RESULT

    # Set result to default value
    DOMAIN_RESULT = None

    # Regex for Domains
    matched = re.search(REGEX, string, re.IGNORECASE)
    if matched:
        DOMAIN_RESULT = ''.join(matched.groups())

0 个答案:

没有答案