Search code examples
pythonpython-3.xperformancepython-multiprocessingpyautogui

Multiprocessing and threading are too slow


I'm creating a script to play the new fortnite festival mode(just for fun not trying to beat anyone other than my friends) and while the code works mostly it still misses notes occasionally. I believe this is because the code is just running to slow for the speed of the game. I have seen similair things in guitar hero so I figured python would be fast enough however it doesn't appear to be. I have tried both threading and multiprocessing, as well as just plain code however they all apear to slow. I am using vscode if that helps.

import pyautogui
import multiprocessing

run = True

def a():
    while run:
       if pyautogui.pixel(1010, 1150) [0] == 255:
            pyautogui.keyDown("d")
            pyautogui.keyUp("d")

def b():
    while run:
        if pyautogui.pixel(1200, 1150) [0] == 255:
            pyautogui.keyDown("f")
            pyautogui.keyUp("f")

def c():
    while run:
        if pyautogui.pixel(1400, 1150) [0] == 255:
            pyautogui.keyDown("j")
            pyautogui.keyUp("j")

def d():
    while run:
        if pyautogui.pixel(1560, 1150) [0] == 255:
            pyautogui.keyDown("k")
            pyautogui.keyUp("k")
if __name__ == '__main__':
    process_a = multiprocessing.Process(target=a)
    process_b = multiprocessing.Process(target=b)
    process_c = multiprocessing.Process(target=c)
    process_d = multiprocessing.Process(target=d)

    process_a.start()
    process_b.start()
    process_c.start()
    process_d.start()

    process_a.join()
    process_b.join()
    process_c.join()
    process_d.join()

I've tried all sorts of stuff including cython(I just couldn't get it too work). My code could be flawed and I realize there some timing issues to hit the notes perfectly but, it's still missing quite a few notes. It seems as if it's just on a different part of the code when a note goes by. Please let me know of any fixes.


Solution

  • Python is slow, but not that slow. Games are made for human reaction times, which is around 300ms. Even the slowest programming language can still execute millions of lines in that time.

    What is slow is most likely in the library you are using:

    There is a one-tenth second delay after calling every PyAutoGUI functions to give the user time to slam the mouse into a corner to trigger the fail safe.

    You can disable this failsafe by setting pyautogui.FAILSAFE = False. I HIGHLY RECOMMEND YOU DO NOT DISABLE THE FAILSAFE

    Calling this library from cython code is not going to make it run faster.

    And even without this delay, reading the entire screen from "outside" is potentially slow because a lot of components are involved. (Operating system, CPU, GPU, all have their own buffers and may have to copy stuff around, and also there are just a lot of pixels in a screenshot.)

    Doing all that work four times (from different threads or processes) is not going to make it faster, either. You could try something like this instead, to make sure the library does only one screenshot:

    im = pyautogui.screenshot()
    pix1 = im.getpixel(...)
    pix2 = im.getpixel(...)
    pix3 = im.getpixel(...)
    pix4 = im.getpixel(...)
    

    And maybe read the documentation a bit more to see if they say anything else about performance. Most likely you can and should limit the screenshot to a small area that you are interested in, which may (or may not) make it faster.

    In addition, you should measure how slow things actually are. A first crude way would be to just print time.time() before and after, say, taking a screenshot.