[英]multiprocessing shared memory in pyqt5 python 3.8
I'm a little confused why the following isn't updating the numpy array across processes?我有点困惑为什么以下内容没有跨进程更新 numpy 数组? There are no errors thrown in this, but the main process doesn't reflect the child's update to the shared array sample
.这没有抛出错误,但是主进程没有反映子进程对共享数组sample
的更新。 I'm unsure why this isn't working.我不确定为什么这不起作用。 The example on the shared_memory
page works fine on my machine. shared_memory
页面上的示例在我的机器上运行良好。 The shared events work fine as well.共享事件也能正常工作。 Is this is a Qt-related issue perhaps?这可能是一个与 Qt 相关的问题吗?
import time
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QProgressBar, QPushButton
import multiprocessing
from multiprocessing import shared_memory
import numpy as np
DATA_SIZE = 1
DTYPE = np.int64
class DataPuller(multiprocessing.get_context("spawn").Process):
def __init__(
self,
event,
shared_mem_name,
):
super().__init__()
self.event = event
self.shm = shared_memory.SharedMemory(name=shared_mem_name)
self.sample = np.ndarray(
shape=(DATA_SIZE, 1), dtype=DTYPE, buffer=self.shm.buf)
self.counter = 0
def run(self):
print("child process started")
while not self.event.is_set():
time.sleep(0.1)
self.sample[:, 0] = self.counter
print("child: ", self.sample[0, 0])
self.counter += 1
if self.counter >= 1000:
self.counter = 0
self.shm.close()
print("child process finished")
class Window(QWidget):
def __init__(self, *args, **kwargs):
super(Window, self).__init__(*args, **kwargs)
layout = QVBoxLayout(self)
self.progressBar = QProgressBar(self)
self.timer = QTimer(self)
self.timer.timeout.connect(self.onTimer)
self.progressBar.setRange(0, 1000)
layout.addWidget(self.progressBar)
layout.addWidget(QPushButton('开启线程', self, clicked=self.onStart))
self.counter = 0
self.shared_mem_name = "data"
self.base_array = np.zeros((DATA_SIZE, 1), dtype=DTYPE)
self.shm = shared_memory.SharedMemory(
create=True,
size=self.base_array.nbytes,
name=self.shared_mem_name)
self.sample = np.ndarray(
shape=self.base_array.shape,
dtype=self.base_array.dtype,
buffer=self.shm.buf)
self.event = multiprocessing.Event()
self._process = DataPuller(self.event, self.shared_mem_name)
def onStart(self):
if not self._process.is_alive():
print("main starting process")
self._process.start()
self.timer.start(500)
else:
pass
def onTimer(self):
print("main: ", self.sample[0, 0])
self.progressBar.setValue(self.sample[0, 0])
def closeEvent(self, event):
if self._process.is_alive():
self.event.set()
self._process.join()
self.shm.close()
self.shm.unlink()
self.close()
print("main process finished")
if __name__ == '__main__':
import sys
from PyQt5.QtWidgets import QApplication
app = QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())
The problem is that the Event does not belong to the DataPuller context so it will never enter the while.问题是 Event 不属于 DataPuller 上下文,所以它永远不会进入 while。 The solution is to create the Event using the context.解决方案是使用上下文创建事件。
The problem is that the __init__ method of DataPuller is executed in the initial process where shared memory is created so it is not available for the secondary DataPuller process.问题是DataPuller 的__init__ 方法是在创建共享内存的初始进程中执行的,因此它不能用于辅助DataPuller 进程。 The solution in this case is to create the shared memory in the run method.这种情况下的解决方案是在run方法中创建共享内存。
import time
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QProgressBar, QPushButton
import multiprocessing
from multiprocessing import shared_memory
import numpy as np
DATA_SIZE = 1
DTYPE = np.int64
context = multiprocessing.get_context("spawn")
class DataPuller(context.Process):
def __init__(
self, event, shared_mem_name,
):
super().__init__()
self.event = event
self.shared_mem_name = shared_mem_name
def run(self):
self.shm = shared_memory.SharedMemory(name=self.shared_mem_name)
self.sample = np.ndarray(shape=(DATA_SIZE, 1), dtype=DTYPE, buffer=self.shm.buf)
self.counter = 0
while not self.event.is_set():
time.sleep(0.1)
self.sample[:, 0] = self.counter
print("child: ", self.sample[0, 0])
self.counter += 1
if self.counter >= 1000:
self.counter = 0
self.shm.close()
print("child process finished")
class Window(QWidget):
def __init__(self, *args, **kwargs):
super(Window, self).__init__(*args, **kwargs)
layout = QVBoxLayout(self)
self.progressBar = QProgressBar()
self.timer = QTimer(self)
self.timer.timeout.connect(self.onTimer)
self.progressBar.setRange(0, 1000)
layout.addWidget(self.progressBar)
layout.addWidget(QPushButton("开启线程", clicked=self.onStart))
self.counter = 0
self.shared_mem_name = "data"
self.base_array = np.zeros((DATA_SIZE, 1), dtype=DTYPE)
self.shm = shared_memory.SharedMemory(
create=True, size=self.base_array.nbytes, name=self.shared_mem_name
)
self.sample = np.ndarray(
shape=self.base_array.shape,
dtype=self.base_array.dtype,
buffer=self.shm.buf,
)
self.event = context.Event()
print(self.event.is_set())
self._process = DataPuller(self.event, self.shared_mem_name)
def onStart(self):
if not self._process.is_alive():
print("main starting process")
self._process.start()
self.timer.start(500)
else:
pass
def onTimer(self):
print("main: ", self.sample[0, 0])
self.progressBar.setValue(self.sample[0, 0])
def closeEvent(self, event):
if self._process.is_alive():
self.event.set()
self._process.join()
self.shm.close()
self.shm.unlink()
self.close()
print("main process finished")
if __name__ == "__main__":
import sys
from PyQt5.QtWidgets import QApplication
app = QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.