Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/357.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python多处理共享内存;一次写入,多次读取_Python_Arrays_Multiprocessing_Pipe_Shared Memory - Fatal编程技术网

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。您确实必须为每个工作人员创建一个队列(或
管道
),以便可靠地向每个工作人员获取数据。请记住,
队列
只是一个带有附加锁和信号量的
管道。因此,您也可以使用
管道
,参见我的第二个示例。由于管道在默认情况下是双向的,因此您还可以使用它将消息从工作者发送回父级。