首页 > 解决方案 > 多处理时如何删除重复项?

问题描述

我对多处理非常陌生,我只是用它在屏幕上查找图像,问题是代码会产生重​​复,这会减慢它的速度我尝试使用“not in”语句仅将 proc 放入进程中还没有,但这不起作用。欢迎任何帮助或优化我不知道我在做什么,因为这只是一个学习多处理的个人项目。

from multiprocessing.context import Process
import pyautogui as auto
screenWidth, screenHeight = auto.size()
currentMouseX, currentMouseY = auto.position()
def bot(aim):
    while True:
        for aim in auto.locateAllOnScreen(r"dot.png", confidence=0.9795):
            auto.click(aim)
            print(aim)
def bot2(aim):
    while True:
        for aim in auto.locateAllOnScreen(r"dot.png", confidence=0.9795):
            auto.click(aim)
            print(aim)
def bot3(aim):
    while True:
        for aim in auto.locateAllOnScreen(r"dot.png", confidence=0.9795):
            auto.click(aim)
            print(aim)            
            
if __name__ == "__main__":
    processes = []
    for t in auto.locateAllOnScreen(r"dot.png", confidence=0.9795):
        proc = Process(target=bot, args=(t,))    
        processes.append(proc)
        proc.start()
    for z in auto.locateAllOnScreen(r"dot.png", confidence=0.9795):
        proc = Process(target=bot2, args=(z,))    
        processes.append(proc)
        proc.start()
    for x in auto.locateAllOnScreen(r"dot.png", confidence=0.9795):    
        proc = Process(target=bot3, args=(x,))    
        processes.append(proc)
        proc.start()
    for p in processes:
        p.join()

标签: pythonmultiprocessing

解决方案


除非我的眼睛欺骗了我,否则您具有三个功能botbot2并且bot3看起来是相同的。您必须问自己为什么需要三个仅在名称上有所不同的相同功能。我当然没有答案。

假定auto.locateAllOnScreen返回屏幕上所有“dot.png”出现的位置,并且您希望并行打印每个出现的信息。您的主要过程是迭代所有这些事件 3 次,并且每次出现都盯着一个新进程。然后每个进程完全忽略传递给它的发生参数目标,而是迭代所有事件本身。因此,如果屏幕上有 5 次出现,您将创建 3 * 5 = 15 个进程,并且每个进程将打印 5 行输出(每次出现一个),总共 15 * 5 = 75 行输出,而实际上如果您正确执行此操作,您应该只获得 5 行输出(我忽略了while True:循环,然后重复所有输出)。您还可能创建比计算机上的 CPU 内核数量更多的进程,因此假设bot函数是 CPU 密集型的,它们不会真正并行运行,但情况可能并非如此。

我不确定这个问题是否适合多处理,因为创建进程以及将参数和结果从一个进程传递到另一个进程会产生相当多的开销。因此,您可能不会在性能上获得任何改进。但是,如果这个想法是看看你将如何使用多处理来解决这个问题,那么我建议如果你事先不知道调用auto.locateAllOnScreen可能会返回多少元素,并认识到创建比数量更多的进程没有意义您实际拥有的处理器,那么最好使用固定大小的多处理池

您想要做的是让您的工作函数bot(并且您只需要其中一个)被传递给它将处理的单个事件。然后,您创建一个进程池,等于您拥有的 CPU 数量和您实际必须提交的任务数量中的较小值。然后,您向池提交许多任务,其中每个任务指定执行该任务的工作函数及其所需的参数。

在下面的代码中,我从函数中删除了永不终止botwhile True:循环。如果你愿意,你可以把它放回去。

from multiprocessing import Pool, cpu_count
import pyautogui as auto

def bot(aim):
    # do the work for the single occurrence of aim
    auto.click(aim)
    print(aim)            
            
if __name__ == "__main__":
    aims = list(auto.locateAllOnScreen(r"dot.png", confidence=0.9795))
    # choose appropriate pool size:
    pool = Pool(min(len(aims), cpu_count()))
    # bot will be called for each element returned by call to auto.locateAllOnScreen
    pool.map(bot, aims)

推荐阅读