python 多进程共享普通对象的实例

python中的线程,因为GIL锁的问题,实际上同时执行的永远都是一个线程,不能充分发挥多核cpu的能力。多进程可以使用多个cpu,但是不能像多线程之间那么方便的共享变量和对象。比如说,在主线程创建了一个对象App,在子线程中检测App的数据发生了变化,从而执行某一动作。在多线程环境中,由于App是共享的,所以可以很方便的写出下面的代码。

#!/usr/bin/python3
# -*- coding: utf-8 -*-
import os
import time
from threading import Thread
from multiprocessing import Process


class App:
    def __init__(self):
        self.set_data(0, 0)

    def get_data(self):
        return self.x, self.y

    def set_data(self, x, y):
        self.x = x
        self.y = y


def RunApp(app):
    while True:
        data = app.get_data()
        if data[0] > 10:
            print("big data: ", data)
            print("exit child thread")
            break
        else:
            print("small data: ", data)
        time.sleep(1)


if __name__ == "__main__":
    app = App()
    thrd = Thread(target=RunApp, args=(app,)) # using thread, app is shared
    # thrd = Process(target=RunApp, args=(app,)) # using process, app is copied
    thrd.start()
    time.sleep(5)  # child thead will print small data several times
    app.set_data(20, 20)  # child thread print big data and exit
    thrd.join()

上面的代码输出如下:

small data:  (0, 0)
small data:  (0, 0)
small data:  (0, 0)
small data:  (0, 0)
small data:  (0, 0)
big data:  (20, 20)
exit child thread

主线程和子线程的app是同一个对象,所以在主线程修改了app的data,在线程可以检测到。 

如果使用多进程的方式,讲上段代码中的Thead改为Process,那么由于对象不共享,子进程实际是复制了一个app,在主进程中的改变不会影响到子进程,因为程序就不会结束,一直输出“small data”。

在进程之间共享对象,参考python多进程文档,大概有三种方法,但是要共享自定义的Class,则只能勇士Manager这种方法。Manager是一个单独的服务端进程,对共享对象进行管理,其他进程通过socket的方式连接到Manager进程,获取对象,从而可以使用对象的公共方法。对上面的代码的略作修改,多进程的实现方式如下:

#!/usr/bin/python3
# -*- coding: utf-8 -*-
import os
import time
from multiprocessing import Process
from multiprocessing.managers import BaseManager


class App:
    def __init__(self):
        self.set_data(0, 0)

    def get_data(self):
        return self.x, self.y

    def set_data(self, x, y):
        self.x = x
        self.y = y


app = App()


class RobotManager(BaseManager):
    pass


RobotManager.register("get_app", lambda: app)
m = RobotManager(address="fuckworld.com", authkey=b"Fuck, world")
m.start()


def RunApp():
    m = RobotManager(address="fuckworld.com", authkey=b"Fuck, world")
    m.connect()
    app = m.get_app()
    while True:
        data = app.get_data()
        if data[0] > 10:
            print("big data: ", data)
            print("exit child process")
            break
        else:
            print("small data: ", data)
        time.sleep(1)


if __name__ == "__main__":
    p = Process(target=RunApp)
    p.start()
    app = m.get_app()  # 必须使用这一句,不然的话,修改不是共享的
    time.sleep(5)  # child process will print small data several times
    app.set_data(20, 20)  # child process print big data and exit
    p.join()

这种方式,服务端和客户端甚至可以运行在不同的机器上,大家可以试一试。当然address可能不能是”fuckworld.com"了。

你可能感兴趣的:(python)