多处理 - 使用不同的输入文件调用函数

时间:2016-08-29 16:53:16

标签: python multiprocessing

我有一个读取文件的函数,将该文件中的记录与另一个文件中的记录进行比较,并根据规则将文件中的记录追加到两个列表中的一个列表中。

我有一个空列表,用于将匹配的结果添加到:

restrictions

我有一个列表match,我希望将一系列文件中的记录与。

进行比较

我有一个函数可以读取我希望看到的文件是否包含任何匹配项。如果匹配,我会将记录附加到def link_match(file): links = json.load(file) for link in links: found = False try: for other_link in other_links: if link['data'] == other_link['data']: match.append(link) found = True else: pass else: print "not found" 列表。

list_files=[]
for file in glob.glob("/path/*.json"):
    list_files.append(file)

我有许多我希望比较的文件,因此我希望使用多处理库。

我创建一个文件名列表作为函数参数:

map

然后我使用if __name__ == '__main__': pool = multiprocessing.Pool(processes=6) pool.map(link_match,list_files) pool.close() pool.join() 功能使用不同的输入文件调用该函数:

match

CPU使用通过屋顶,通过在函数循环中添加打印行,我可以看到正在找到匹配并且函数表现正常。

但是,$cmd="curl -XGET 'https://lookups.twilio.com/v1/PhoneNumbers/+1201832xxxx?Type=carrier&Type=caller-name' -u 'clientidxxxxxx:clienttokenxxxxxx' "; $result=shell_exec($cmd); $response = json_decode($result); echo "<pre>"; print_r($response); echo "</pre><br/>"; 结果列表仍为空。我做错了什么?

4 个答案:

答案 0 :(得分:1)

多处理创建多个进程。你&#34;匹配的背景&#34;变量现在将在该子进程中,而不是启动处理的父Python进程。

尝试将列表结果写入函数中的文件以查看我的意思。

答案 1 :(得分:1)

要扩展cthrall的答案,您需要从函数中返回一些内容,以便将信息传递回主线程,例如

def link_match(file):
    [put all the code here]
    return match

[main thread]
all_matches = pool.map(link_match,list_files)

将从每个单个线程返回列表matchmap将返回此列表中的列表列表。然后,您可以flatten再次获得最终输出。

或者你可以使用shared list,但这会让我更加头疼。

答案 2 :(得分:1)

multiprocessing为池中的每个进程运行一个新的Python实例 - 上下文为空(如果使用spawn作为启动方法)或复制(如果使用fork ),以及你传递的任何参数的副本(无论哪种方式),并从那里他们全部分开。如果您想在分支机构之间传递数据,还有其他几种方法可以实现。

  1. 不是写入内部列表,而是写入文件并在以后完成时从中读取。这里最大的潜在问题是,一次只能有一件东西可以写入文件,所以要么你制作了很多单独的文件(之后必须阅读所有文件),要么它们都会相互阻塞。
  2. 继续multiprocessing,但使用multiprocessing.Queue代替列表。这是专门为您当前的用例提供的对象:使用多个进程并需要在它们之间传递数据。假设您确实应该使用multiprocessing(您的情况对threading不会更好,请参见下文),这可能是您的最佳选择。
  3. 使用threading而不是multiprocessing。单独的线程都共享一个环境。这里最大的问题是Python只允许一个线程实际上每个进程运行Python代码。这称为全局解释器锁(GIL)。因此,当线程在外部进程(其他程序,用户输入,读取或写入文件)上等待时,threading非常有用,但如果大部分时间都花在Python代码上,那么它实际上需要更长的时间(因为它需要更长的时间)一点时间切换线程,你没有做任何事情来节省时间)。它有自己的queue。如果你使用threading,你应该使用它而不是普通的列表 - 否则,如果它在错误的情况下切换线程,则两个线程同时访问列表的可能性相互干扰时间。
  4. 哦,顺便说一下:如果你确实使用了线程,那么Python 3.2及更高版本的GIL实现了改进,看起来它至少有很好的帮助机会。很多线程性能的东西很大程度上取决于你的硬件(CPU核心数量)和你正在做的确切任务 - 可能最好尝试几种方法,看看哪些方法适合你。

答案 3 :(得分:1)

当进行多处理时,每个子进程都会获得自己在if __name__ == '__main__':语句之前定义的主模块中的任何全局变量的副本。这意味着每个进程中的link_match()函数将访问代码中的不同的 match列表。

一种解决方法是使用共享列表,这又需要SyncManager来同步对进程间共享资源的访问(通过调用multiprocessing.Manager()创建)。然后,这将用于创建列表以在下面的代码中存储结果(我将其命名为matches而不是match)。

我还必须使用functools.partial()创建一个可以从修订后的link_match函数调用的单个参数,该函数现在需要两个参数,而不是一个(函数pool.map()期望的那种) )。

from functools import partial
import glob
import multiprocessing

def link_match(matches, file):  # note: added results list argument
    links = json.load(file)
    for link in links:
        try:
            for other_link in other_links:
                if link['data'] == other_link['data']:
                    matches.append(link)
                else:
                    pass
        else:
            print "not found"

if __name__ == '__main__':
    manager = multiprocessing.Manager()  # create SyncManager
    matches = manager.list()  # create a shared list here
    link_matches = partial(link_match, matches)  # create one arg callable to
                                                 # pass to pool.map()
    pool = multiprocessing.Pool(processes=6)
    list_files = glob.glob("/path/*.json")  # only used here
    pool.map(link_matches, list_files)  # apply partial to files list
    pool.close()
    pool.join()
    print(matches)