Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/360.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Python';从一条长输入行计算整数和的多重处理_Python_Python 2.7_Python Multiprocessing - Fatal编程技术网

使用Python';从一条长输入行计算整数和的多重处理

使用Python';从一条长输入行计算整数和的多重处理,python,python-2.7,python-multiprocessing,Python,Python 2.7,Python Multiprocessing,我想将Python的多处理模块用于以下方面: 将输入行映射到整数列表并计算该列表的总和 输入行最初是一个字符串,其中要求和的项用空格分隔 我尝试的是: from itertools import imap my_input = '1000000000 ' * int(1e6) print sum(imap(int, my_input.split())) 这在我的机器上大约需要600毫秒,但我希望通过多处理加快速度 瓶颈似乎在映射部分,因为sum方法在应用于整型列表时非常快: >>

我想将Python的多处理模块用于以下方面: 将输入行映射到整数列表并计算该列表的总和

输入行最初是一个字符串,其中要求和的项用空格分隔

我尝试的是:

from itertools import imap

my_input = '1000000000 ' * int(1e6)
print sum(imap(int, my_input.split()))
这在我的机器上大约需要600毫秒,但我希望通过多处理加快速度

瓶颈似乎在映射部分,因为sum方法在应用于整型列表时非常快:

>>> int_list = [int(1e9)] * int(1e6)
>>> %time sum(int_list)
CPU times: user 7.38 ms, sys: 5 µs, total: 7.38 ms
Wall time: 7.4 ms
>>> 1000000000000000

我尝试应用中的说明,但由于我对使用多处理非常陌生,我无法将说明用于此问题。

因此,这似乎大致可以归结为三个步骤:

  • 制造
  • 在该池中的列表中映射int()
  • 总结结果
  • 因此:

    在可能的情况下,使用发电机可能更有效率:

    if __name__ == '__main__':
        import multiprocessing
        import re
        my_input = '1000000000 ' * int(1e6)
        # use a regex iterator matching whitespace
        string_list = (x.group(0) for x in re.finditer(r'[^\s]+\s', my_input))
        # Pool over all CPUs
        int_list = multiprocessing.Pool().imap(int, string_list)
        print sum(int_list)
    
    正则表达式可能比
    split
    慢,但是使用
    re.finditer
    应该允许
    池在进行单个拆分时尽快开始映射,并且使用
    imap
    而不是
    map
    应该对
    sum
    执行类似的操作(允许它在可用时开始添加数字)。归功于
    re.finditer
    idea

    对于多进程来说,它可能比在单个进程中进行更有效,也可能不更有效。你可能会浪费更多的时间来制定新的流程,并将结果反馈给他们,而不是一次完成所有的事情。如果您尝试将加法也放入池中,情况也是如此


    在我正在测试的系统上,它有两个CPU,我得到一个进程解决方案大约在半秒钟内运行,非生成器多进程解决方案大约在1秒内运行,生成器解决方案大约在12-13秒钟内运行。

    因此,这似乎大致可以归结为三个步骤:

  • 制造
  • 在该池中的列表中映射int()
  • 总结结果
  • 因此:

    在可能的情况下,使用发电机可能更有效率:

    if __name__ == '__main__':
        import multiprocessing
        import re
        my_input = '1000000000 ' * int(1e6)
        # use a regex iterator matching whitespace
        string_list = (x.group(0) for x in re.finditer(r'[^\s]+\s', my_input))
        # Pool over all CPUs
        int_list = multiprocessing.Pool().imap(int, string_list)
        print sum(int_list)
    
    正则表达式可能比
    split
    慢,但是使用
    re.finditer
    应该允许
    池在进行单个拆分时尽快开始映射,并且使用
    imap
    而不是
    map
    应该对
    sum
    执行类似的操作(允许它在可用时开始添加数字)。归功于
    re.finditer
    idea

    对于多进程来说,它可能比在单个进程中进行更有效,也可能不更有效。你可能会浪费更多的时间来制定新的流程,并将结果反馈给他们,而不是一次完成所有的事情。如果您尝试将加法也放入池中,情况也是如此


    在我正在测试的系统上,它有两个CPU,我得到一个进程解决方案大约在半秒钟内运行,非生成器多进程解决方案大约在1秒内运行,生成器解决方案大约在12-13秒钟内运行。

    使用Unix系统的一个名为的功能,您可以以零开销从父进程读取(而不是写入)数据。通常情况下,您必须复制数据,但在Unix中分叉进程可以避免这种情况

    使用此方法,池中的作业可以访问整个输入字符串并提取它将处理的部分。然后,它可以自行拆分和解析字符串的这一部分,并返回其部分中的整数之和

    from multiprocessing import Pool, cpu_count
    from time import time
    
    
    def serial(data):
        return sum(map(int, data.split()))
    
    
    def parallel(data):
        processes = cpu_count()
    
        with Pool(processes) as pool:
            args = zip(
                ["input_"] * processes, # name of global to access
                range(processes), # job number
                [processes] * processes # total number of jobs 
            )
            return sum(pool.map(job, args, chunksize=1))
    
    
    def job(args):
        global_name, job_number, total_jobs = args
        data = globals()[global_name]
        chunk = get_chunk(data, job_number, total_jobs)
    
        return serial(chunk)
    
    
    def get_chunk(string, job_number, total_jobs):
        """This function may mess up if the number of integers in each chunk is low (1-2).
        It also assumes there is only 1 space separating integers."""
        approx_chunk_size = len(string) // total_jobs
    
        # initial estimates
        start = approx_chunk_size * job_number
        end = start + approx_chunk_size
    
        if start and not string.startswith(" ", start - 1):
            # if string[start] is not beginning of a number, advance to start of next number
            start = string.index(" ", start) + 1
    
        if job_number == total_jobs:
            # last job
            end = None
        elif not string.startswith(" ", end - 1):
            # if string[end] is part of a number, then advance to end of number
            end = string.index(" ", end - 1)
    
        return string[start:end]
    
    
    def timeit(func, *args, **kwargs):
        "Simple timing function"
        start = time()
        result = func(*args, **kwargs)
        end = time()
        print("{} took {} seconds".format(func.__name__, end - start))
        return result
    
    
    if __name__ == "__main__":
    #    from multiprocessing.dummy import Pool # uncomment this for testing
    
        input_ = "1000000000 " * int(1e6)
    
        actual = timeit(parallel, input_)
        expected = timeit(serial, input_)
        assert actual == expected
    

    使用Unix系统的一个名为的功能,您可以从父进程读取(而不是写入)数据,而开销为零。通常情况下,您必须复制数据,但在Unix中分叉进程可以避免这种情况

    使用此方法,池中的作业可以访问整个输入字符串并提取它将处理的部分。然后,它可以自行拆分和解析字符串的这一部分,并返回其部分中的整数之和

    from multiprocessing import Pool, cpu_count
    from time import time
    
    
    def serial(data):
        return sum(map(int, data.split()))
    
    
    def parallel(data):
        processes = cpu_count()
    
        with Pool(processes) as pool:
            args = zip(
                ["input_"] * processes, # name of global to access
                range(processes), # job number
                [processes] * processes # total number of jobs 
            )
            return sum(pool.map(job, args, chunksize=1))
    
    
    def job(args):
        global_name, job_number, total_jobs = args
        data = globals()[global_name]
        chunk = get_chunk(data, job_number, total_jobs)
    
        return serial(chunk)
    
    
    def get_chunk(string, job_number, total_jobs):
        """This function may mess up if the number of integers in each chunk is low (1-2).
        It also assumes there is only 1 space separating integers."""
        approx_chunk_size = len(string) // total_jobs
    
        # initial estimates
        start = approx_chunk_size * job_number
        end = start + approx_chunk_size
    
        if start and not string.startswith(" ", start - 1):
            # if string[start] is not beginning of a number, advance to start of next number
            start = string.index(" ", start) + 1
    
        if job_number == total_jobs:
            # last job
            end = None
        elif not string.startswith(" ", end - 1):
            # if string[end] is part of a number, then advance to end of number
            end = string.index(" ", end - 1)
    
        return string[start:end]
    
    
    def timeit(func, *args, **kwargs):
        "Simple timing function"
        start = time()
        result = func(*args, **kwargs)
        end = time()
        print("{} took {} seconds".format(func.__name__, end - start))
        return result
    
    
    if __name__ == "__main__":
    #    from multiprocessing.dummy import Pool # uncomment this for testing
    
        input_ = "1000000000 " * int(1e6)
    
        actual = timeit(parallel, input_)
        expected = timeit(serial, input_)
        assert actual == expected
    

    非常感谢。除了缺少主节点周围的配额外,这是有效的,但正如您所暗示的,这实际上要慢得多(执行现在需要大约3秒)。@starkbot修复了引号。另外,当您发布该消息时,是否正在进行其他添加-尝试迭代器版本?可能会因可用CPU的数量而有所不同。我认为基于
    多处理
    的版本速度慢得多并不奇怪,因为您在这里只能同时执行单个
    int
    调用。:-]@好吧,是的。这是如何使用多处理和池的一个很好的基本示例,即使特定的作业对它来说不是一个好的作业。@DavidHeyman第二个版本给出了以下错误:ValueError:invalid literal for int(),以10为基数:“”谢谢!除了缺少主节点周围的配额外,这是有效的,但正如您所暗示的,这实际上要慢得多(执行现在需要大约3秒)。@starkbot修复了引号。另外,当您发布该消息时,是否正在进行其他添加-尝试迭代器版本?可能会因可用CPU的数量而有所不同。我认为基于
    多处理
    的版本速度慢得多并不奇怪,因为您在这里只能同时执行单个
    int
    调用。:-]@好吧,是的。这是一个很好的基本示例,说明了如何使用多处理和池,即使特定作业不适合它。@DavidHeyman第二个版本给出了以下错误:ValueError:invalid literal for int(),以10为基数:“”您使用的是什么操作系统?一个更大的问题是拆分字符串将非常耗时,将拆分后的子字符串发送到进程池也是如此。在Unix上,您可以避免直接将子字符串发送到子进程,甚至可以将拆分委托给子进程。@Dunes我正在使用OS X。如何避免发送子字符串并委托拆分?
    多处理
    在这里没有帮助,因为serialisati