Python多处理共享内存;一次写入,多次读取
系统Python多处理共享内存;一次写入,多次读取,python,arrays,multiprocessing,pipe,shared-memory,Python,Arrays,Multiprocessing,Pipe,Shared Memory,系统 Linux(Manjaro KDE) Python 3.8.3 程序: 我有UDP端口上的传入字符串数据。在使用选择器监视UDP端口之前,主循环会对进程进行后台处理。我希望每个进程都可以使用不断更新的UDP数据 已尝试: from multiprocessing import Process, Array from ctypes import c_char_p import time def worker(arr): count = 0 while True:
- Linux(Manjaro KDE)
- Python 3.8.3
我有UDP端口上的传入字符串数据。在使用选择器监视UDP端口之前,主循环会对进程进行后台处理。我希望每个进程都可以使用不断更新的UDP数据 已尝试:
from multiprocessing import Process, Array
from ctypes import c_char_p
import time
def worker(arr):
count = 0
while True:
count += 1
val = 'val' + str(count)
arr[0] = val
print(arr[:])
time.sleep(2)
def main():
arr = Array(c_char_p, 1)
p = Process(target=worker, args=(arr,))
p.daemon = True
p.start()
while True:
print(arr[:])
try:
print(arr[:].decode('utf-8'))
except :
pass
# try:
# val = arr[:]
# val = val.decode('utf-8')
# print(f'main {val}')
# except:
# pass
time.sleep(1)
if __name__ == "__main__":
main()
'''
from multiprocessing import Process, Array
from ctypes import c_char_p
import time
def worker(arr):
count = 0
while True:
count += 1
val = 'val' + str(count)
arr[0] = bytes(val, 'utf-8')
print(arr[:])
time.sleep(2)
def main():
arr = Array(c_char_p, 1)
p = Process(target=worker, args=(arr,))
p.daemon = True
p.start()
while True:
print(arr[:])
try:
print(arr[:].decode('utf-8'))
except :
pass
time.sleep(1)
if __name__ == "__main__":
main()
if __name__ == "__main__":
main()
'''
- maxsize=1的多处理队列令人头痛,很快就崩溃了
- 多处理阵列(我现在就在这里)
- 管道。我有一种感觉,这可能是一条路要走。但我已经深陷未知领域;我以前从未用过
我想从子进程访问UDP数据-这些是camera_view方法 伪UDP字符串
import socket
import random
import datetime
import time
conn = ('127.0.0.1', 6666)
def rand_value(f_val, t_val):
result = round(random.uniform(f_val, t_val), 2)
result = random.uniform(f_val, t_val)
return result
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while True:
time.sleep(6)
timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
overlay = timestamp
for i in range(9):
val = rand_value(i*10, i*10+10)
if i == 8: val = 'TASK: Im the real Batman'
overlay = overlay + "," + str(val)
print(overlay)
sock.sendto(overlay.encode(), conn)
我的节目
import datetime
import selectors
import socket
import time
from multiprocessing import Lock, Process, Queue
from multiprocessing.sharedctypes import Array
from ctypes import c_char_p
REQUIRED_CAMERAS = 1
CAMERA_CONN = {'name':['Colour Camera'], 'ip':['127.0.0.1'], 'port':[9000]}
OVERLAY_CONN = ('0.0.0.0', 6666)
CONTROL_CONN = ('0.0.0.0', 6667)
NUMBER_OF_ITEMS_IN_OVERLAY = 10
class Camera():
def __init__(self, cam_name, cam_ip, cam_port):
self.ip = cam_ip
self.port = cam_port
self.capture = cv2.VideoCapture(0)
self.frame_width = int(self.capture.get(3))
self.frame_height = int(self.capture.get(4))
self.name = cam_name
def get_overlay(data_packet):
data = data_packet.decode()
data = data.split(',')
field0 = data[0]
field1 = 'KP: ' + str(round(float(data[1]), 3))
field2 = 'DCC: ' + str(round(float(data[2]), 2)) + 'm'
field3 = 'E: ' + str(round(float(data[3]), 2)) + 'm'
field4 = 'N: ' + str(round(float(data[4]), 2)) + 'm'
field5 = 'D: ' + str(round(float(data[5]), 2)) + 'm'
field6 = 'H: ' + str(round(float(data[6]), 2)) # + '°'
field7 = 'R: ' + str(round(float(data[7]), 2)) # + '°'
field8 = 'P: ' + str(round(float(data[8]), 2)) # + '°'
field9 = data[9]
x = []
for i in range(NUMBER_OF_ITEMS_IN_OVERLAY):
x.append(eval('field' + str(i)).encode())
# if i == 0:
# print(x[i])
return x
def socket_reader(sock, mask, q, REQUIRED_CAMERAS, overlay):
data_packet, sensor_ip = sock.recvfrom(1024)
sensor_port = sock.getsockname()[1]
print(f'SENSOR PORT {sensor_port} and SENSOR_IP {sensor_ip}')
if sensor_port == OVERLAY_CONN[1]:
x = get_overlay(data_packet)
for i in range(len(x)):
overlay[i] = x[i]
print(f'Socket Reader {overlay}')
def camera_view(CAMERA_CONN, cam_name, camera, overlay_q, control_q, overlay):
while True:
print(f'PROCESS {camera} RUNNING FOR: {cam_name}')
try:
print(f'Camera View {overlay}')
for i in range(len(overlay)):
print(overlay[i])
except:
pass
time.sleep(1)
def controller(REQUIRED_CAMERAS, CAMERA_CONN, OVERLAY_CONN, CONTROL_CONN):
if REQUIRED_CAMERAS > len(CAMERA_CONN['name']):
print(f'REQURIED_CAMERAS: {REQUIRED_CAMERAS} - more than connections in CAMERA_CONN ')
else:
# Set up a UDP connection for the overlay string and the control commands
sock_overlay = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock_control = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock_overlay.bind(OVERLAY_CONN)
sock_control.bind(CONTROL_CONN)
# Set up the selector to watch over the socket
# and trigger when data is ready for reading
sel = selectors.DefaultSelector()
sel.register(fileobj=sock_overlay, events=selectors.EVENT_READ, data=socket_reader)
sel.register(fileobj=sock_control, events=selectors.EVENT_READ, data=socket_reader)
# create shared memory
overlay_q = Queue(maxsize=1)
control_q = Queue(maxsize=1)
overlay = Array(c_char_p, range(NUMBER_OF_ITEMS_IN_OVERLAY))
print(f'Init Overlay {overlay}')
# Generate the processes; one per camera
processes = []
for camera in range(REQUIRED_CAMERAS):
processes.append(Process(target=camera_view, args=(CAMERA_CONN, CAMERA_CONN['name'][camera], camera, overlay_q, control_q, overlay)))
for process in processes:
process.daemon = True
process.start()
# Spin over the selector
while True:
# Only have one connnection registered, so to stop
# the loop spinning up the CPU, I have made it blocking
# with the timeout = 1 (sec) instead of =0.
events = sel.select(timeout=None)
for key, mask in events:
# the selector callback is the data= from the register above
callback = key.data
# the callback gets the sock, mask and the sensor queues
if key.fileobj == sock_overlay:
callback(key.fileobj, mask, overlay_q, REQUIRED_CAMERAS, overlay)
else:
callback(key.fileobj, mask, control_q, REQUIRED_CAMERAS, overlay)
if __name__ == "__main__":
controller(REQUIRED_CAMERAS, CAMERA_CONN, OVERLAY_CONN, CONTROL_CONN)
EDIT1:
from multiprocessing import Process, Array
from ctypes import c_char_p
import time
def worker(arr):
count = 0
while True:
count += 1
val = 'val' + str(count)
arr[0] = val
print(arr[:])
time.sleep(2)
def main():
arr = Array(c_char_p, 1)
p = Process(target=worker, args=(arr,))
p.daemon = True
p.start()
while True:
print(arr[:])
try:
print(arr[:].decode('utf-8'))
except :
pass
# try:
# val = arr[:]
# val = val.decode('utf-8')
# print(f'main {val}')
# except:
# pass
time.sleep(1)
if __name__ == "__main__":
main()
'''
from multiprocessing import Process, Array
from ctypes import c_char_p
import time
def worker(arr):
count = 0
while True:
count += 1
val = 'val' + str(count)
arr[0] = bytes(val, 'utf-8')
print(arr[:])
time.sleep(2)
def main():
arr = Array(c_char_p, 1)
p = Process(target=worker, args=(arr,))
p.daemon = True
p.start()
while True:
print(arr[:])
try:
print(arr[:].decode('utf-8'))
except :
pass
time.sleep(1)
if __name__ == "__main__":
main()
if __name__ == "__main__":
main()
'''
EDIT2:感谢@RolandSmith,我坚持排队,我想我已经有了一个前进的模板。请参阅下面的代码。如果我不能让这个在程序中运行,我会回到这里
from multiprocessing import Process, Queue
import time
import datetime
def worker(camera, q):
val = ''
while True:
if q.full() == True:
val = q.get()
else:
val = val
print(f'WORKER{camera} {val}')
time.sleep(0.2)
def main():
cameras = 2
processes = []
queues = []
for camera in range(cameras):
queues.append(Queue(maxsize=1))
processes.append(Process(target=worker, args=(camera, queues[camera])))
for process in processes:
process.daemon = True
process.start()
while True:
for q in queues:
if not q.empty():
try:
_ = q.get()
except:
pass
else:
q.put(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
time.sleep(.5)
if __name__ == "__main__":
main()
在我看来,使用
队列
比使用数组
更不容易出错
下面是第二个示例,转换为使用队列:
来自多处理导入进程,队列
导入时间
def工人(q):
计数=0
尽管如此:
计数+=1
val='val'+str(计数)
q、 put(val)
打印('worker:',val)
时间。睡眠(2)
def main():
q=队列()
p=进程(目标=工作者,参数=(q,))
p、 daemon=True
p、 开始()
尽管如此:
如果不是q.empty():
print('main:',q.get())
时间。睡眠(1)
如果名称=“\uuuuu main\uuuuuuuu”:
main()
这将产生:
> python3 test3.py
worker: val1
main: val1
worker: val2
main: val2
worker: val3
main: val3
worker: val4
main: val4
worker: val5
下面是使用管道的相同示例:
来自多处理导入进程的管道
导入时间
def工人(p):
计数=0
尽管如此:
计数+=1
val='val'+str(计数)
p、 发送(val)
打印('worker:',val)
时间。睡眠(2)
def main():
子级,父级=管道()
p=进程(目标=工作者,参数=(子对象)
p、 daemon=True
p、 开始()
尽管如此:
如果parent.poll():
打印('main:',parent.recv())
时间。睡眠(1)
如果名称=“\uuuuu main\uuuuuuuu”:
main()
这将产生与上一个示例相同的结果
此外,默认情况下,管道是双向的。
因此,您还可以将工作人员的数据发送回父级。首先是用于提交系统信息的道具。很多人忘了做那件事。现在谈谈我的评论。提交时,您的程序介于真实程序和真实程序之间,这使它令人困惑。你能把它清理一下,把没用的零件取下来吗?现在转到队列的问题。“这让人头疼,很快就崩溃了”是什么意思?看看get_overlay
,为什么不直接将字段
放入数组,而不是使用eval
?@RolandSmith,谢谢您的回复。我添加了一个编辑。注释掉的块可以工作,但它只输出脚本中键入的“test”。当我尝试编程一个字符串时,没有(空白)。@RolandSmith。我对队列的问题是将它们与锁一起正确地传递。消费者的阅读速度将远远快于生产者,我希望消费者继续使用旧数据,直到新数据可用。每当你从队列
中获取某个内容时,它就会从队列
中消失。因此,在worker中,必须使用Queue.empty()
。如果返回True
,则重新使用以前检索到的数据。好人。我开始查看该数组,发现我需要a=c_wchar_p,因为我一定在Py2中找到了示例。由于您的输入,我将再次沿着队列
路径前进。我没有这样做的原因是,我有多个员工希望使用相同的数据。这意味着queue.put将位于main中,而q.get将位于worker中。如果我有4个工人,我会简单地重复q.put 4x工作,还是会有一个工人可能会放慢速度而错过?我想我必须为每个工作人员创建一个q。您确实必须为每个工作人员创建一个队列(或管道
),以便可靠地向每个工作人员获取数据。请记住,队列
只是一个带有附加锁和信号量的管道。因此,您也可以使用管道
,参见我的第二个示例。由于管道在默认情况下是双向的,因此您还可以使用它将消息从工作者发送回父级。