Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Многопроцессорность с серийным объектом в качестве параметра

Автор вопроса: codingCatОтветов: 1

У меня проблема с Python и я передаю серийный объект в качестве параметра отдельному процессу. Программа запускается в Windows 8, поэтому использование глобальных переменных не вариант.

from multiprocessing import Queue
from multiprocessing import Process
import os
import serial
from serial.tools import list_ports
from time import sleep

displayMessages = Queue()
modemPort = None

def processDisplayMessages(displayMessages):
    while True:
        msg = displayMessages.get()  #should halt until message in queue
        print msg

def processIncomingSerialMessages(modemPort, displayMessages):
    while True:
        line = modemPort.readline()
        displayMessages.put(line)

def main():
    print "Serial Send Test"
    Process(target=processDisplayMessages, args = (displayMessages,)).start()
    modemPort = serial.Serial('COM5', 57600, timeout=0.9)  # open first serial port
    Process(target=processIncomingSerialMessages, args = (modemPort, displayMessages)).start()
    print "Back from launch"

    sleep(0.1)

 if __name__ == '__main__':
    main()

Когда программа запускается, я получаю следующую ошибку:

Process Process-2:
Traceback (most recent call last):
  File "c:\python27\lib\multiprocessing\process.py", line 258, in _bootstrap
    self.run()
  File "c:\python27\lib\multiprocessing\process.py", line 114, in run
    self._target(*self._args, **self._kwargs)
  File "C:\Users\matthew.parets\Documents\..Development\RaspberryPi\windows\seri
alRecvPrototype.py", line 27, in processIncomingSerialMessages
    line = modemPort.readline()
  File "c:\python27\lib\site-packages\serial\serialwin32.py", line 246, in read
    if not self.hComPort: raise portNotOpenError
AttributeError: 'Serial' object has no attribute 'hComPort'

Если я помещаю открытый для последовательного порта (modemPort) в качестве первой строки processIncomingSerialMessages, программа работает нормально. Проблема в том, что мне нужно разделить ввод и вывод модема, поэтому мне нужно передать серийный объект в качестве параметра. А Python, похоже, это не нравится.

Может ли кто-нибудь увидеть мою ошибку или предложить альтернативу?

pythonparametersserial-portmultiprocessingmodem

Ответы

Ответ 1 · рейтинг 3 · Tim Peters

Я не могу запустить этот код, но я был бы удивлен, если бы он сработал: аргумент, передаваемый между процессами, работает, обрабатывая объект аргумента на стороне отправки, отправляя строку рассола между процессами через канал или сокет и распаковывая это строка на принимающей стороне. Я не знаю ни одного случая с открытыми объектами ввода-вывода, для которых это могло бы работать (файлы, сокеты, каналы ...). Типы объектов ввода-вывода не просто имеют внутреннее состояние данных, они также связаны с ресурсами, которые сам Python не реализует. Рассол - это просто поток необработанных байтов.

Вы уже догадались, что вам нужно открыть последовательный порт в рабочем процессе. Увы, я не знаю, что означает "Мне нужно разделить ввод и вывод от модема", поэтому трудно предложить обходной путь. Но я уверен, что вы поймете это, если примете то, что вы уже обнаружили на собственном горьком опыте: передача открытого последовательного объекта между процессами никогда не сработает.

Тем не менее, вы можете покопаться в различных протоколах травления и создать свой собственный класс с настраиваемым кодом травления / распаковки, который (повторно) открывал серийный объект, когда его не отбирали. Это был бы сложный способ скрыть то, что в противном случае было бы простым кодом для (повторного) открытия последовательного объекта в рабочих процессах.

РЕДАКТИРОВАТЬ: вопросы и ответы

И снова Windows не предлагает простого выхода из глобальных переменных, поэтому я застрял в одном процессе, обрабатывающем и отправку, и получение.

"Глобальная переменная", вероятно, вам не поможет. Я предполагаю, что вы имеете в виду fork(), но ничто не является общим для fork(): дочерние процессы видят копии адресного пространства родительского процесса. Уловки ввода-вывода также часто не работают правильно.

Предоставляет ли Python способ передать значение по ссылке или ссылочное значение в процесс? Я попытался добавить серийный объект в списки и наборы с теми же результатами. Опять же, предоставляет ли Python что-то вроде объекта или массива из Java, через которые я мог бы получить ссылку, не будучи "маринованным"?

Во всех современных ОС существует очень высокая стена между процессами. Чтобы что-то действительно разделялось между процессами, вам нужно использовать для этого типы, созданные с нуля, или использовать средства "разделяемой памяти" ОС.

Вы можете прочитать документацию для multiprocessing.sharedctypes, в которой описаны способы использования разделяемой (между процессами) памяти. Но, как предупреждают документы:

Примечание. Хотя можно сохранить указатель в общей памяти, помните, что это будет относиться к месту в адресном пространстве определенного процесса. Однако указатель, скорее всего, окажется недействительным в контексте второго процесса, и попытка разыменования указателя из второго процесса может вызвать сбой.

Это не сработает. Это не проблема языка программирования, это проблема ОС. sharedctypes полезен для таких вещей, как массивы int и float.

Чтобы это приложение работало (телеметрия в реальном времени), процесс приема должен постоянно оставаться в рабочем состоянии.

Извините, я не слежу за этим в контексте. В своем вопросе вы сказали: "Если я помещу открытый для последовательного порта (modemPort) в первую строку processIncomingSerialMessages, программа будет работать нормально". processIncomingSerialMessages имеет бесконечный цикл после этого. В каком смысле это нарушает "процесс приема должен оставаться в рабочем состоянии все время"?

В показанном вами коде не кажется существенной разницы, открыт ли последовательный порт в рабочем процессе или в основном процессе (если последний действительно работал), и действительно, вы сказал, что все будет нормально, если вы сделаете это по-прежнему. Так что же плохого в том, чтобы делать это таким образом? В самом деле, зачем вообще использовать для этого рабочий процесс? Основная программа, которую вы показали, ничего не делает (кроме сна на десятые доли секунды) после запуска обоих рабочих процессов, так почему бы не позволить основной программе быть "процессом приема"?

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы