函数返回错误类型的值,如果我使用多进程。

huangapple go评论60阅读模式
英文:

Function return value of wrong type if I use multiprocessing

问题

以下是您要翻译的代码部分:

import concurrent.futures

def get_data():
    with concurrent.futures.ProcessPoolExecutor() as executor:
        x = executor.submit(replace_elements, first(), elements_for_replace)
        y = executor.submit(replace_elements, second(), elements_for_replace)
        z = executor.submit(replace_elements, third(), elements_for_replace)
    destroyAllWindows()
    return x, y, z

在新版本的代码中,由于您使用了concurrent.futures来并行执行函数,返回的变量是<class 'concurrent.futures._base.Future'>而不是<class 'list'>。要获取<class 'list'>的返回值,您可以在executor.submit后使用.result()来获取结果。这是修改后的代码:

import concurrent.futures

def get_data():
    with concurrent.futures.ProcessPoolExecutor() as executor:
        x = executor.submit(replace_elements, first(), elements_for_replace)
        y = executor.submit(replace_elements, second(), elements_for_replace)
        z = executor.submit(replace_elements, third(), elements_for_replace)
    destroyAllWindows()
    return x.result(), y.result(), z.result()

这将确保get_data()函数返回与第一个版本的代码相同的<class 'list'>类型的结果。

英文:

world!
I have this code:

from numpy import array
from cv2 import imshow, cvtColor, imwrite, imread, destroyAllWindows, COLOR_BGR2RGB
from pyscreenshot import grab
import pytesseract


filename = &#39;image.png&#39;
elements_for_replace = {&#39;iL&#39;: &#39;1L&#39;, &#39;Bi&#39;: &#39;B1&#39;, &#39;Bl&#39;: &#39;B1&#39;, &#39;Ci&#39;: &#39;C1&#39;, &#39;Cl&#39;: &#39;C1&#39;}

pytesseract.pytesseract.tesseract_cmd = r&#39;C:\Users\Administrator\AppData\Local\Tesseract-OCR\tesseract.exe&#39;


def scanning(x1, y1, x2, y2):
    screen = array(grab(bbox=(x1, y1, x2, y2)))
    imwrite(filename, screen)
    img = imread(filename)
    text = pytesseract.image_to_string(img)
    history = text.split()
    return history


def first():
    return scanning(730, 740, 1335, 790)


def second():
    return scanning(730, 453, 1335, 500)


def third():
    return scanning(817, 45, 1522, 99)


def replace_elements(data, replace_data):
    for item in data:
        if item in replace_data:
            data[data.index(item)] = replace_data[item]
    return data


def get_data():
    x = replace_elements(first(), elements_for_replace)
    y = replace_elements(second(), elements_for_replace)
    z = replace_elements(third(), elements_for_replace)
    destroyAllWindows()
    return x, y, z

When the function get_data() is called, this code uses computer vision to translate an image into text at three different locations on the screen. Does it consistently. It then replaces the failed elements with the correct ones. At the output, we get a tuple of lists (x, y, z), which will be processed by another part of the program.

Converting images to text takes a lot of time. And the sequential execution of the program multiplies this time by 3. I came to the conclusion that I need to use the multiprocessing module (or rather concurrent.futures) to reduce the program execution time.

I rewrote the function get_data() like this:

import concurrent.futures


def get_data():
    with concurrent.futures.ProcessPoolExecutor() as executor:
        x = executor.submit(replace_elements, first(), elements_for_replace)
        y = executor.submit(replace_elements, second(), elements_for_replace)
        z = executor.submit(replace_elements, third(), elements_for_replace)
    destroyAllWindows()
    return x, y, z

Now the returned variables have data type <class 'concurrent.futures._base.Future'> instead of <class 'list'> and the program, trying to process this data, throws an error 'TypeError: 'Future' object is not subscriptable'.

How to start parallel execution of a function so that the return value of the function is the same as in the first version of the code, that is <class 'list'> ???

答案1

得分: 2

executor.submit() 返回一个 Future 对象,而不是被调用函数的值。为了获取函数返回的值,您必须在 Future 对象上调用 result()。在您的情况下,您需要修改您的代码如下:

def get_data():
    with concurrent.futures.ProcessPoolExecutor() as executor:
        future_x = executor.submit(replace_elements, first(), elements_for_replace)
        future_y = executor.submit(replace_elements, second(), elements_for_replace)
        future_z = executor.submit(replace_elements, third(), elements_for_replace)
    destroyAllWindows()

    # 实际上获取函数的值
    x = future_x.result()
    y = future_y.result()
    z = future_z.result()

    return x, y, z

此外,作为建议,您还可以考虑使用 ProcessPoolExecutor.map() 来简化代码。使用它,您无需定义每个结果。

英文:

executor.submit() returns a Future object, not the value of the function called. In order to get the value returned by the function, you must call result() on the Future object. In your case you'll want to modify your code like so:

def get_data():
    with concurrent.futures.ProcessPoolExecutor() as executor:
        future_x = executor.submit(replace_elements, first(), elements_for_replace)
        future_y = executor.submit(replace_elements, second(), elements_for_replace)
        future_z = executor.submit(replace_elements, third(), elements_for_replace)
    destroyAllWindows()

    # Actually get the value of the function here
    x = future_x.result()
    y = future_y.result()
    z = future_z.result()

    return x, y, z

Additionally, as a suggestion you could also look into using the ProcessPoolExecutor.map() to clean up the code a bit. With it, you wouldn't have to define each result.

huangapple
  • 本文由 发表于 2023年3月21日 01:47:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/75793631-3.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定