【问题标题】:How can I share an updated values in dictionary among different process?如何在不同进程之间共享字典中的更新值?
【发布时间】:2016-04-02 12:41:13
【问题描述】:

我是这里的新手,也是 Python 的新手。我有一个关于字典和多处理的问题。我想在我的 Raspberry Pi 的第二个内核上运行这部分代码(首先是运行 GUI 应用程序)。所以,我创建了一个字典(keys(20) + 数组,每个键的长度为 256 - 下面的脚本只是一个简短的例子)。我在一个单独的脚本中初始化了这个字典,并将这个字典中的所有值都设置为零。脚本 table1.py(这个字典应该在两个内核中都可用)

diction = {}
diction['FrameID']= [0]*10
diction['Flag']= ["Z"]*10

在第二个脚本(应该在第二个内核上运行)中,我读取了从串口获取的值,并根据适当的位置将它们放入/设置到这个字典中(解析+转换)。由于我通过串行端口获取大量信息,因此信息一直在变化。脚本 Readmode.py

from multiprocessing import Process
import time
import serial
import table1

def replace_all(text, dic):
for i, j in dic.iteritems():
    text = text.replace(i, j)
return text
def hexTobin(hex_num):
scale = 16 ## equals to hexadecimal
num_of_bits = len(hex_num)*4
bin_num = bin(int(hex_num, scale))[2:].zfill(num_of_bits) #hex to binary
return bin_num

def readSerial():
port = "/dev/ttyAMA0"
baudrate = 115200
ser = serial.Serial(port, baudrate, bytesize=8, parity=serial.PARITY_NONE, stopbits=1, xonxoff=False, rtscts=False)
line = []
for x in xrange(1):
    ser.write(":AAFF:AA\r\n:F1\r\n")        # new           
    while True:
        for c in ser.read():
            line.append(c)
            a=''.join(line[-2:])
            if a == '\r\n':
                b=''.join(line)
                print("what I get:" + b) 
                c=b[b.rfind(":"):len(b)] #string between last ":" start delimiter and stop delimiter
                reps = {':':'', '\r\n':''} #throw away start and stop delimiter
                txt = replace_all(c, reps)   
                print("hex num: " + txt) 
                bina_num=hexTobin(txt) # convert hex to bin
                print("bin num: " + bina_num)
                ssbit = bina_num[:3] # first three bits 
                print("select first three bits: " + ssbit)
                abit=int(ssbit,2) # binary to integer 
                if abit == 5:
                    table1.diction['FrameID'][0]=abit
                    if abit == 7:
                        table1.diction['FrameID'][5]=abit         
                        print("int num: ",abit)
                        print(table1.diction)
                        line = []
                        break
                        ser.close()

p1=Process(target=readSerial)
p1.start() 

在此期间,我想阅读这本词典中的信息并将它们用于另一个过程。但是当我尝试读取该值时,所有值都为零。

我的问题是如何创建一个可用于两个进程并可以根据从串行端口获取的数据进行更新的字典? 提前感谢您的回答。

【问题讨论】:

  • 由于问题可能出在您的代码中,我们需要看到它才能回答。理想情况下是精简版。

标签: python-2.7 dictionary serial-port multiprocessing


【解决方案1】:

在 Python 中,当您启动两个不同的脚本时,即使它们导入了一些通用模块,它们也不会共享任何内容(代码除外)。如果两个脚本都是import table1,那么它们都有自己的table1 模块实例,因此它们都有自己的table1.diction 变量实例。

如果你想一想,它必须是那样的。否则,所有 Python 脚本将共享相同的 sys.stdout,例如。因此,同时执行的两个不同脚本之间或多或少不会共享任何内容。

multiprocessing 模块允许您从同一个脚本创建多个进程。因此,您需要将您的 GUI 和阅读功能合并到同一个脚本中。但是你可以做你想做的事。您的代码将如下所示:

import multiprocessing

# create shared dictionary sd

p1=Process(target=readSerial, args = (sd,)
p1.start()

# create the GUI behaviour you want

但请稍等。这也行不通。因为当创建Process 时,它会启动 Python 解释器的一个新实例并再次创建它自己的所有实例,就像启动一个新脚本一样。所以即使是现在,默认情况下readSerial 中的任何内容都不会与 GUI 进程共享。

但幸运的是,multiprocessing 模块提供了一些显式技术来在进程之间共享数据。有不止一种方法可以做到这一点,但这里有一个可行的方法:

import multiprocessing
import time

def readSerial(d):
    d["test"] = []
    for i in range(100):
        l = d["test"]
        l.append(i)
        d["test"] = l
        time.sleep(1)

def doGUI(d):
    while True:
        print(d)
        time.sleep(.5)


if __name__ == '__main__':
    with multiprocessing.Manager() as manager:
        sd = manager.dict()

        p = multiprocessing.Process(target=readSerial, args=(sd,))
        p.start()

        doGUI(sd)

您会注意到readSerial 函数中对列表的追加有点奇怪。那是因为我们在这里使用的字典对象不是普通的字典。它实际上是一个字典proxy,它隐藏了用于在两个进程之间发送数据的管道。当我附加到字典内的列表时,需要通知代理(通过分配给字典),以便它知道通过管道发送更新的数据。这就是为什么我们需要赋值(而不是简单地直接改变字典中的列表)。有关更多信息,请查看docs

【讨论】:

  • 能否请您提供信息,如何将其用于具有更多键且每个键都有值数组的字典(如我的示例中)?
  • 不知道为什么会有什么不同?共享字典是一个代理,但您可以像字典一样使用它:您对它所做的更改将传递回另一个进程,我已在答案中添加了更多详细信息,但如果您仍然卡住,您需要向我展示哪一点代码仍然给您带来问题。
  • 当我从串口读取数据时,我想把它们放在指定的位置。示例:我得到带有 frameID 的框架(这些 ID 总是在 1 到 256 之间)和其他信息。我想把这些数据总是放在同一个地方,所以如果 frameID 是 124,我想把这个框架的所有信息写在同一个地方 -> dict {['Flag'][123]} = 5, dict {['Dsc' ][123]="on" 等等。在 GUI 中,我只需调用键并放入我想要的数组中。我希望这是可以理解的。
  • 如果我在每帧通过串口发送后正确理解这一点,我会在字典中添加一个额外的位置。那么,如果我得到 1000 帧,我将有 1000 个额外的位置(列)?那么,我需要以某种方式限制吗?
  • 这些问题涉及不同的主题。问题是如何在两个进程之间共享字典。我建议你把到目前为止的代码放在一起,如果你仍然卡住,可以问一个不同的问题。
猜你喜欢
  • 2016-11-20
  • 1970-01-01
  • 2012-06-17
  • 2011-01-30
  • 1970-01-01
  • 2021-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多