Python multiprocessing:启动进程后multiprocessing.Value恢复默认值问题
问题分析与解决方法
问题根源
- 普通实例变量丢失(如bind_port):
在Windows系统的spawn进程启动模式下,子进程会重新导入模块并创建Process子类实例,父进程初始化时设置的普通实例变量不会被子进程继承;即使是Unix的fork模式,若后续修改父进程变量,子进程也无法同步。 - laser_password为空:
使用multiprocessing.Value(c_wchar_p, ...)时,c_wchar_p是指向宽字符的指针,进程启动后指针指向的内存地址在子进程中无效,导致值变为空字符串。
解决步骤
1. 修复普通变量的进程共享
将需要跨进程保留的普通变量(如bind_port)改为multiprocessing.Value类型,确保值能在进程间共享:
# 替换原bind_port初始化代码 self.bind_port = multiprocessing.Value('i', int(kwargs["bind_port"]) if "bind_port" in kwargs else 0) # 后续访问时使用.value属性 print(self.bind_port.value)
2. 修复字符串类型的进程共享
不要用指针类型存储字符串,改用以下两种可靠方式:
方式一:使用multiprocessing.Manager().Value
from multiprocessing import Manager manager = Manager() # 替换原laser_password初始化代码 self.laser_password = manager.Value(str, kwargs.get("laser_password", self.DEFAULT_PASSWORD)) # 直接通过.value访问/修改 logger.info(f"Current password: {self.laser_password.value}")
方式二:使用multiprocessing.Array
适合固定长度的字符串:
password_str = kwargs.get("laser_password", self.DEFAULT_PASSWORD) # 定义最大长度(示例为20),编码为字节 self.laser_password = multiprocessing.Array('c', password_str.encode('utf-8'), lock=True) # 读取时解码 current_pwd = self.laser_password.value.decode('utf-8').rstrip('\x00') # 修改时重新编码赋值 self.laser_password.value = "new_password".encode('utf-8')
3. 兼容Windows的spawn模式
确保启动代码放在if __name__ == '__main__':保护块内,避免子进程重复初始化模块:
if __name__ == '__main__': emulator = EmulatorViron(bind_port=30800, laser_password="helloworld") emulator.start() emulator.join()
4. 完整修改后的核心代码片段
class EmulatorViron(multiprocessing.Process): BIND_PORT_RANGE = [30800, 30900] socket = None DEFAULT_PASSWORD = "" COOLING_TEMP_MIN = 15.0 COOLING_TEMP_MAX = 90.0 HEATING_COEF = 2.5 # roughly degrees / sec COOLING_COEF = 2.0 # roughly degrees / sec def __init__(self, **kwargs): super().__init__() logger.info(f"Received kwargs: {kwargs}") # 改用Value存储bind_port self.bind_port = multiprocessing.Value('i', int(kwargs["bind_port"]) if "bind_port" in kwargs else 0) self.socket = None # Initialize version self.device_identifier = kwargs.get("device_identifier", "VIRON") # 用Manager的Value存储密码 from multiprocessing import Manager manager = Manager() self.laser_password = manager.Value(str, kwargs.get("laser_password", self.DEFAULT_PASSWORD)) logger.info(f"Current password: {self.laser_password.value}") # 其他普通变量也改用Value确保共享 self.operation_delay = multiprocessing.Value('f', kwargs.get("operation_delay", 1.0)) self.delay_between_commands = multiprocessing.Value('f', kwargs.get("delay_between_commands", 0.1)) # 原有状态变量保持不变 self.user_authenticated = multiprocessing.Value(c_bool, kwargs.get("user_authenticated", False)) self.fire_mode = multiprocessing.Value(c_bool, kwargs.get("fire_mode", False)) self.standby_mode = multiprocessing.Value(c_bool, kwargs.get("standby_mode", False)) self.is_flashing = multiprocessing.Value(c_bool, kwargs.get("is_flashing", False)) self.is_switching = multiprocessing.Value(c_bool, kwargs.get("is_switching", False)) self.user_shots = multiprocessing.Value("i", kwargs.get("user_shots", 8001)) self.fl_mode_int = multiprocessing.Value(c_bool, kwargs.get("fl_mode", True)) self.qs_mode_int = multiprocessing.Value(c_bool, kwargs.get("qs_mode", True)) self.qs_delay = multiprocessing.Value("i", kwargs.get("qs_delay", 50)) self.cooling_temp = multiprocessing.Value("f", kwargs.get("t_cool", self.COOLING_TEMP_MIN)) self.bnc_interlock = multiprocessing.Value(c_bool, kwargs.get("bnc_interlock", False)) self.client_port_name = "" self._initialize_connection() self._running_flag = multiprocessing.Event()
内容的提问来源于stack exchange,提问作者Firebug2309
相关产品推荐
相关产品推荐

