-1

For example I have an Event class which looks like

class Event:
    def __init__(self):
        self.events = dict()

    def on(self, name, callback):
        self.events[name] = callback

    def emit(self, name):
        callback = self.events[name]
        if callable(callback):
            callback()

And when I try to use it in main thread it works.

if __name__ == "__main__":
    event = Event()
    event.on("hello", lambda: print("hello world"))
    event.emit("hello")  # OUTPUT: hello world

But when I try to register my event in another process it is not changed nowhere but same process. I have defined two functions, one of those sets new event and other emits that event. Then running those function on different processes.

def soldier(e):
    e.on("hello", lambda: print("hello world"))

def officer(e):
    e.emit("hello")

if __name__ == "__main__":
    event = Event()

    process1 = Process(target=officer, args=(event,))
    process2 = Process(target=soldier, args=(event,))

    process1.start()
    process2.start()

    process1.join()
    process2.join()

The expected resul is the same as above example without processes but getting error as the first process changes the value of event.events only inside of it and the changed value is not visible outside of the process.

How to see the changed value of custom class object outside of the process?

martineau
  • 112,593
  • 23
  • 157
  • 280
Artyom Vancyan
  • 2,348
  • 3
  • 10
  • 28
  • Processes and threads are very different in this respect, so the answer would depend on which of them you're asking about — otherwise your question is too broad. – martineau Jan 02 '22 at 17:36
  • Just I've tried the same with threads, but more interested in Processes – Artyom Vancyan Jan 02 '22 at 18:27
  • 1
    It's more complicated with processes because they each run in their own memory space, so there are no truly global variables they can "share" (unlike with threads). There are several different ways of working around that, one of which is by using a "proxy" that coordinates concurrent access the resource. See my answer to [Working with deque object across multiple processes](https://stackoverflow.com/questions/54511731/working-with-deque-object-across-multiple-processes) for an example. – martineau Jan 02 '22 at 19:17

1 Answers1

1

If you want to use Process, you need to use a pipe, a messaging mechanism or a some method to share data between different processes. Each time you start a process (with Process), the data are cloned, so 3 variables event exists in 3 processes (the main process and the 2 processes that are created).

It is simpler here to use threads that are light processes that share the same memory space. In the example below the variable event is shared.

import threading

class Event:
    def __init__(self):
        self.events = dict()

    def on(self, name, callback):
        self.events[name] = callback

    def emit(self, name):
        if name in self.events:
            callback = self.events[name]
            if callable(callback):
                callback()

def officer(e):
    e.on("hello", lambda: print("hello world"))

def soldier(e):
    e.emit("hello")

if __name__ == "__main__":
    event = Event()

    thread1 = threading.Thread(target=officer, args=(event,))
    thread2 = threading.Thread(target=soldier, args=(event,))

    thread1.start()
    thread2.start()

    thread1.join()
    thread2.join()
    

Moreover you must also add a secure mechanism to ensure the entry has been registered before using it. The order of creation of the threads (or processes) does not ensure the code is executed in the same order.

Eric Marchand
  • 589
  • 2
  • 10
  • Thanks for this solution but I would like to use Process, so how to share memory between processes? – Artyom Vancyan Jan 02 '22 at 18:53
  • If you want to work with the multiprocessing module you can have a look at Pipe or Queue for example. You can also have to "shared memory" methods. – Eric Marchand Jan 02 '22 at 19:00
  • `Lock` does not help in this case. But `shared_memory` can be helpful. Thank you! – Artyom Vancyan Jan 02 '22 at 19:04
  • For threading you need to use a `Lock` to prevent concurrent access — which you are *not* doing in your answer — so it's not doing things correctly. – martineau Jan 02 '22 at 19:21
  • The topic is about sharing data between dynamic entities (threads or processes). In the answer I say that the order of execution is not guarantee between threads and that some synchronization mechanism is needed. I have just inserted a simple test of self.events in emit() to avoid a crash "key error" (unlikely but theorically possible). – Eric Marchand Jan 03 '22 at 09:01
  • My point was that your code claims to be showing how to use threads, but it's not doing it correctly. – martineau Jan 03 '22 at 21:17