简体   繁体   中英

How to make a secondary process continually update a variable through ProcessPoolExecutor in python

Well met

I'm trying to use pyautogui to run some simple checks, I'm attempting to make the main process detect a visual input, then start a sub process that continually updates a shared variable with the Y position of a different image as it moves through the screen until it disappears.

Unfortunately I'm barely a programmer so I keep getting stuck on the execution, so I wanted to ask for help. This is the code I wrote,

import pyautogui
import time
import importlib
foobar = importlib.import_module("cv2")
foocat = importlib.import_module("concurrent")
import numpy
import concurrent.futures

with concurrent.futures.ProcessPoolExecutor() as executor:
    CheckingInput = executor.submit(CheckPositionInput)
    CheckingImage = executor.submit(CheckPositionImage)

print(XMark, YMark)
print(time.time() - startingtime)

def CheckPositionInput():

    Checked = False
    global XImage, YImage, XMark, YMark, AreaOnScreen
    while not Checked:
        print('Searching')
        if pyautogui.locateCenterOnScreen('Area.png', confidence=0.8) != None:
            Checked = True
            AreaOnScreen = True
            XMark, YMark = pyautogui.locateCenterOnScreen('Area.png', confidence=0.8)

def CheckPositionImage():
    global XImage, YImage, XMark, YMark, AreaOnScreen
    print('start')
    while not AreaOnScreen:
        print('Waiting')
        while AreaOnScreen:
            if pyautogui.locateCenterOnScreen('Image.png', confidence=0.6) != None:
                XMark, YMark = pyautogui.locateCenterOnScreen('Image.png', confidence=0.6)
                print(YMark)
                print('Checking')

The problems I've run into go from the while loop in CheckPositionImage closing and dying after a single loop, to the while loop in CheckPositionImage getting stuck and stopping the check position process, and that no matter what I try I can't manage to update the crucial Ymark variable properly outside the process.

It's important to understand that global variables are not read/write sharable across multiple processes. A child process can possibly inherit such a variable value (depends on what platform you are running) and read its value, but once a process assigns a new value to that variable, this change is not reflected back to any other process. This is because every process runs in its own address space and can only modify its copy of a global variable. You would need to use instead shared memory variables created by the main process and passed to its child processes. But let's ignore this fundamental problem for now and assume that global variables were sharable.

If I follow your code correctly, this is what you appear to be doing:

  1. The main process submits two tasks to a multiprocessing pool to be processed by worker functions CheckPositionInput and CheckPositionImage and then waits for both tasks to complete to print out global variables XMark and YMark , presumably set by the CheckPositionImage function.
  2. CheckPositionImage is effectively doing nothing until CheckPositionInput sets global variable AreaOnScreen to True , which only occurs after the call pyautogui.locateCenterOnScreen('Area.png', confidence=0.8) returns a value that is not None . When this occurs, checked is set to True and your loop terminates effectively terminating the task.
  3. When varibale AreaOnScreen is set to True (in step 2. above), function CheckPositionImage finally enters into a loop calling pyautogui.locateCenterOnScreen('Image.png', confidence=0.6) . When this function returns a value that is not None a couple of print statements are issued and the loop is re-iterated.

To the extent that my analysis is correct , I have a few comments:

  1. This CheckPositionImage task never ends since variable AreaOnSCreen is neither ever reset to False nor is a return nor break statement issued in the loop. I assume this is an oversight and once we are returned a non- None value from our call to pyautogui.locateCenterOnScreen , we should return. My assumption is based on the fact that without this termination occurring, the main process's block beginning with concurrent.futures.ProcessPoolExecutor() as executor: will never complete (there is am implicit wait for all submitted tasks to complete) and you will therefore never fall through to the subsequent print statements.
  2. You never initialize variable startingtime .
  3. Function CheckPositionInput sets global variables XMark and YMark , whose values are never referenced by either the main process or function pyautogui.locateCenterOnScreen('Image.png', confidence=0.6) . What is the point in calling this function a second time with identical arguments to set these variables that are never read?

You have processes running, but the actual processing is essentially sequential : The main process does nothing until both child processes it has created end and one child process does nothing useful until the other child process sets a flag when its terminating. I see, therefore, no reason for using multiprocessing at all. Your code could be simply (note that I have renamed variables and functions according to Python's PEP8 coding conventions :

import pyautogui
import time
# What is the purpose of these next 3 commented-out statements?
#import importlib
#foobar = importlib.import_module("cv2")
#foocat = importlib.import_module("concurrent")

def search_and_check():
    print('Searching...')
    while True:
        if pyautogui.locateCenterOnScreen('Area.png', confidence=0.8) != None:
            # What is the purpose of this second call, which I have commented out?
            # Note that the values set, i.e. xMark and yMark, are never referenced.
            #xMark, yMark = pyautogui.locateCenterOnScreen('Area.png', confidence=0.8)
            break
    print('Checking...')
    while True:
        result = pyautogui.locateCenterOnScreen('Image.png', confidence=0.6)
        if result != None:
            return result

starting_time = time.time()
xMark, yMark = search_and_check()
print(xMark, yMark)
print(time.time() - starting_time)

Could/should the two different calls to pyautogui.locateCenterOnScreen be done in parallel?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM