【问题标题】:Queue or Lock in child multiprocess在子多进程中排队或锁定
【发布时间】:2017-10-24 20:11:34
【问题描述】:

我在这个网站上已经有一段时间了,我发现了很多有用的解决方案来解决我在构建我的第一个 python 程序时遇到的问题。我希望你们能再次帮助我。

我正在尝试启动数量不定的多进程,每个进程都使用一小部分列表进行扫描。我一直在修改队列,但是当我实现它们时,它们总是给我的循环增加大量时间。我希望最大限度地提高我的速度,同时保护我的 Titles.txt 免受错误内容的影响。让我告诉你我的代码。

l= ['url1', 'url2', etc]

def output(t):  
    f = open('Titles.txt','a')
    f.write(t)
    f.close()

def job(y,processload):
    calender = ['Jan', 'Feb', 'Mar', 'Dec']   #the things i want to find
    for i in range(processload):              #looping processload times
        source = urllib.request.urlopen(l[y]).read()      #read url #y
        soup = bs.BeautifulSoup(source,'lxml')
            for t in soup.html.head.find_all('title'):
                if any(word in t for word in calender):  
                    output(t)                 #this what i need to queue
    y+=1                                      #advance url by 1

if __name__ == '__main__':
    processload=5                 #the number of urls to be scanned by job
    y=0                           #the specific count of url in list
    runcount = 0
    while runcount == 0:          #engage loop 
        for i in range(380/processload):      #the list size / 5
            p= multiprocessing.Process(target=job, args=(y,processload)
            p.start()
            y+=processload        #jump y ahead

上面的代码允许在我的循环中实现最大速度。我想在保持速度的同时保护我的输出。我一直在搜索示例,但我还没有找到具有在子进程中启动的锁或队列的代码。你会建议我如何进行?

非常感谢。

【问题讨论】:

  • 我假设您需要创建一个 Queue 并将其作为元组中的另一个参数传递。然后每个进程可以将t 推送到队列中。然后,当进程退出时(您将需要它们的集合并加入所有进程),您可以将队列处理为“Titles.txt”
  • 由于进程会无限循环,我是否需要在for i in range之后在循环中运行写入?
  • 我不知道您所说的无休止回收是什么意思,但是您要么等待所有进程完成(在每个 Process 上调用 join())然后为队列服务,要么您也启动另一个ProcessQueue 下沉到文件中。
  • 那么,为了等待进程完成,我需要o=output(t),o.join()吗?
  • 不,看我的回答。

标签: python performance queue locking multiprocessing


【解决方案1】:

此示例代码执行我认为您希望程序执行的操作:

import multiprocessing as mp
import time
import random

# Slicing a list into sublists from SilentGhost
# https://stackoverflow.com/a/2231685/4834
def get_chunks(input_list, chunk_size):
    return [input_list[i:i+chunk_size] for i in range(0, len(input_list), chunk_size)]

def find_all(item):
    ''' Dummy generator to simulate fetching a page and returning interesting stuff '''
    secs = random.randint(1,5)
    time.sleep(secs)
    # Just one yield here, but could yield each item found
    yield item


def output(q):
    ''' Dummy sink which prints instead of writing to a file '''
    while True:
        item = q.get()
        if item is None:
            return
        print(item)

def job(chunk, q):
    for item in chunk:
        for t in find_all(item):
            q.put(t)
    print('Job done:', chunk)



if __name__ == '__main__':
    all_urls = ['url1', 'url2', 'url3', 'url4', 'url5', 'url6']

    chunks = get_chunks(all_urls, 2)
    q = mp.Queue()
    # Create processes, each taking a chunk and the queue
    processes = [mp.Process(target=job, args=(chunk,q)) for chunk in chunks]

    # Start them all
    for p in processes:
        p.start()

    # Create and start the sink
    sink = mp.Process(target=output, args=(q,))
    sink.start()

    # Wait for all the jobs to finish
    for p in processes:
        p.join()

    # Signal the end with None
    q.put(None)

    sink.join()

示例输出:

url3
Job done: ['url3', 'url4']
url4
url5
url1
Job done: ['url5', 'url6']
url6
Job done: ['url1', 'url2']
url2

【讨论】:

  • 首先,非常感谢。我访问了您提供的链接。他的建议正是我想要做的,以一种更有效的方式。此外,您的方法对我正在尝试做的事情非常有效。我能够非常轻松地调整我的代码,并且我最初的问题得到了很好的回答。但是,我想知道是否可以将第二个参数传递给队列?我现在 yield info 其中 info 是 url 和有趣的东西的简短描述,但我想添加第二个变量,以便我可以确定在 output() 中写入文件的位置 if myvar ==
  • 元组在 Python 中非常出色,您只需将它们制作成这样:(a,b,c),然后它们可以作为函数之间的单个参数传递,直到您需要像这样解压缩它们:a,b,c = arg。你也可以在 Stackoverflow 上提出一个单独的问题。
猜你喜欢
  • 1970-01-01
  • 2015-03-21
  • 2022-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-13
  • 1970-01-01
相关资源
最近更新 更多