Как я могу обновить членов класса в процессах?

Я искал другие вопросы, и этот вопрос без ответа - единственный, который я смог найти, который каким-то образом охватывает эту проблему и не очень полезен. Кроме того, мне нужно, чтобы это работало с процессами, а не с потоками.

Итак, с самого начала я написал пример программы, чтобы показать свою проблему, вы сможете вставить ее, и она запустится:

import multiprocessing
import time 

class Apple:
   def __init__(self, color):
      self.color = color

def thinkAboutApple(apple):
   while True:
      print(apple.color)
      time.sleep(2)

my_apple = Apple("red")
new_process = multiprocessing.Process(target=thinkAboutApple, args=(my_apple,))
new_process.start()
time.sleep(4)
print("new: brown")
my_apple.color = "brown"

#so that the program doesn't exit after time.sleep(4)
while True:
    pass
# actual output | # wanted output
red             | red
red             | red
new: brown      | new: brown
red             | brown
red             | brown

Это говорит мне, что либо яблоко находится в странном предположении, что оно имеет два цвета одновременно, ИЛИ что яблоко нового_процесса находится в другом месте в оперативной памяти и отделено от яблока в основном процессе.

Итак, вопрос: есть ли способ, чтобы указатель яблока в процессе указывал на одно и то же яблоко, или как питонический способ сохранить все экземпляры яблока во всех процессах одинаковыми? Что, если у меня есть одно и то же яблоко во многих процессах и еще больше процессов без яблока, как мне убедиться, что они всегда одинаковы?

Используйте потоки вместо процессов. Процессы не обмениваются данными, в отличие от потоков. Если вы хотите использовать процессы, вам необходимо предоставить конструкции с общей памятью. Смотрите это.

Jarvis 25.12.2020 21:20

@Jarvis Из этого минимального примера неясно, возможна ли замена процессов потоками.

chepner 25.12.2020 21:23

@Jarvis спасибо за предложение, однако в этой ситуации я намеренно выбрал процессы, а не потоки. Я знаю, что одним из недостатков является сложная коммуникация, но мне нужен параллелизм

Maritn Ge 25.12.2020 21:27

@chepner да, я не думаю, что смогу создать пример, который достаточно прост для вопроса SO, чтобы было ясно, что мне нужны процессы, поэтому я добавил эту информацию в вопрос

Maritn Ge 25.12.2020 21:29

Оформить заказ это

Jarvis 25.12.2020 21:32

@Jarvis Я думаю, что это решение только для python-2, так как в печати нет (), и вставка ответа в пустой .py не запускается, потому что «экземпляр Basemanager не имеет Simpleclass»

Maritn Ge 25.12.2020 21:46

@MaritnGe - Наряду с полученным результатом, не могли бы вы также упомянуть ожидаемый результат?

fountainhead 25.12.2020 21:52

Вы пытаетесь управлять графическим интерфейсом или получить детерминированный вывод от механизма состояний? Вам нужен либо какой-то обмен сообщениями, например docs.python.org/3/library/…, либо вам нужно полностью избавиться от «параллелизма». Я могу получить ожидаемый результат с полным редизайном и отсутствием многопроцессорности, но я полагаю, что это не соответствует вашим потребностям.

Kenny Ostrom 25.12.2020 23:07

@KennyOstrom Боюсь, мне придется использовать много сокетов, каналов и слез, чтобы заставить это работать, я думаю, может быть, я пока попробую это с потоками, чтобы двигаться вперед и продолжать искать решение для обработки.

Maritn Ge 25.12.2020 23:10

Поищите в игре «Жизнь» подход к управлению состоянием. Тогда вам просто нужен основной поток, чтобы спать между состояниями. Один ключевой момент - я не думаю, что вам нужна другая обработка печати. Только одному процессу должно быть разрешено выполнять ввод-вывод.

Kenny Ostrom 25.12.2020 23:11
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
6
10
288
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете получить специализированную версию класса Proxy, используемого multiprocessing.BaseManager, из (недокументированного) класса multiprocessing.managers.NamespaceProxy, который, в отличие от базового класса, предоставляет все свои методы и атрибуты. Это похоже на ответ @shtse8 на связанный повторяющийся вопрос, но я публикую здесь работающий ответ, чтобы прояснить, как это можно сделать.

from multiprocessing import Process
from multiprocessing.managers import BaseManager, NamespaceProxy
import time
import types

class MyManager(BaseManager): pass  # Avoid namespace pollution.

class Apple:
    def __init__(self, color):
        self.color = color


def Proxy(target):
    """ Create a derived NamespaceProxy class for `target`. """
    def __getattr__(self, key):
        result = self._callmethod('__getattribute__', (key,))
        if isinstance(result, types.MethodType):
            def wrapper(*args, **kwargs):
                self._callmethod(key, args)
            return wrapper
        return result

    dic = {'types': types, '__getattr__': __getattr__}
    proxy_name = target.__name__ + "Proxy"
    ProxyType = type(proxy_name, (NamespaceProxy,), dic)  # Create subclass.
    ProxyType._exposed_ = tuple(dir(target))

    return ProxyType


AppleProxy = Proxy(Apple)


def thinkAboutApple(apple):
    while True:
        print(f"apple.color: {apple.color}")
        time.sleep(1)


if __name__ == '__main__':

    MyManager.register('Apple', Apple, AppleProxy)

    manager = MyManager()
    manager.start()

    my_apple = manager.Apple("red")
    new_process = Process(target=thinkAboutApple, args=(my_apple,))
    new_process.start()

    time.sleep(2)  # Allow other process to run a short while.
    my_apple.color = "brown"  # Change shared class instance.

    time.sleep(2)  # Allow other process to run at little while longer.
    new_process.terminate()

Одно небольшое редактирование: содержимое функции-оболочки должно возвращать self._callmethod(key, args, kwargs). В противном случае это проглатывает и игнорирует любые аргументы ключевого слова. И он всегда возвращает None. В противном случае этот ответ именно то, что мне нужно.

Mike Jarvis 03.12.2022 21:46

Другие вопросы по теме