Python3: select () ведет себя странно с UNIX FIFO

Я пытаюсь дождаться UNIX FIFO для некоторой входной строки. Я использую select (), чтобы дождаться, пока FD будет готов к чтению. В первый раз мой код ожидает, как и ожидалось, но затем select () продолжает успешно возвращаться, даже если FD больше не готов к чтению.

Вот мой код:

#! /usr/bin/python3

import errno
import time
import sys
import os
import select
import string

myInput = './inFIFO'
try:
    if os.path.exists(myInput):
        os.unlink(myInput)
    os.mkfifo(myInput)
except Exception as e:
    sys.stderr.write("ERROR: " + str(e))
    sys.exit(2)

sIn = open(myInput, 'r')

try:
    loop = 5
    while loop:
        loop = loop - 1
        readMe = select.select([sIn], [], [])[0]
        print(readMe, file = sys.stderr);
        if len(readMe):
            a = sIn.readlines()
            print('Message <|' + ''.join(a) + '|>', file = sys.stderr)
            sIn.flush()
except Exception as e:
    sys.stderr.write('ERROR: ' + str(e))
    sys.stdin.close()
    sys.stdout.close()
    sys.stderr.close()
    os.unlink(myStdin)
    sys.exit(1)

Вот результат:

root:~# ./select.py &
[1] 4035
root:~# echo 'Hello World !!!' > ./inFIFO
root:~# [<_io.TextIOWrapper name='./inFIFO' mode='r' encoding='UTF-8'>]
Message <|Hello World !!!
|>
[<_io.TextIOWrapper name='./inFIFO' mode='r' encoding='UTF-8'>]
Message <||>
[<_io.TextIOWrapper name='./inFIFO' mode='r' encoding='UTF-8'>]
Message <||>
[<_io.TextIOWrapper name='./inFIFO' mode='r' encoding='UTF-8'>]
Message <||>
[<_io.TextIOWrapper name='./inFIFO' mode='r' encoding='UTF-8'>]
Message <||>

[1]+  Done                    ./select.py
root:~#

Почему select () ведет себя необычно? Я использую LinuxMint 19 amd64 и Python 3.6.6

Обновлено:

Обновил код с os.read() все та же история ...

Новый код:

#! /usr/bin/python3

import errno
import time
import sys
import os
import select
import string

myInput = './inFIFO'
try:
    if os.path.exists(myInput):
        os.unlink(myInput)
    os.mkfifo(myInput)
except Exception as e:
    sys.stderr.write("ERROR: " + str(e))
    sys.exit(2)

sIn = open(myInput, 'r')

try:
    loop = 5
    while loop:
        loop = loop - 1
        readMe = select.select([sIn], [], [])[0]
        print(readMe, file = sys.stderr);
        if len(readMe):
            a = os.read(sIn.fileno(), 8192).decode()
            print('Message <|' + ''.join(a) + '|>', file = sys.stderr)
            sIn.flush()
except Exception as e:
    sys.stderr.write('ERROR: ' + str(e))
    sys.stdin.close()
    sys.stdout.close()
    sys.stderr.close()
    os.unlink(myStdin)
    sys.exit(1)

Теперь вывод:

root:~# ./select.py &
[1] 4099
root:~# echo 'Hello World !!!' > ./inFIFO
root:~# [<_io.TextIOWrapper name='./inFIFO' mode='r' encoding='UTF-8'>]
Message <|Hello World !!!
|>
[<_io.TextIOWrapper name='./inFIFO' mode='r' encoding='UTF-8'>]
Message <||>
[<_io.TextIOWrapper name='./inFIFO' mode='r' encoding='UTF-8'>]
Message <||>
[<_io.TextIOWrapper name='./inFIFO' mode='r' encoding='UTF-8'>]
Message <||>
[<_io.TextIOWrapper name='./inFIFO' mode='r' encoding='UTF-8'>]
Message <||>

[1]+  Done                    ./select.py
root:~#

Не используйте буферизованный ввод-вывод (.readlines) с select.select, они могут странно взаимодействовать. Вместо этого используйте os.read. Пожалуйста, расширьте вопрос с помощью вывода на консоль после замены sIn.readlines() на os.read(sIn.fileno(), 8192).

pts 27.10.2018 09:54
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
1
62
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Мне удалось решить проблему, открыв FIFO как READ-WRITE и NON-BLOCK I / O.

Мой рабочий код:

#! /usr/bin/python3

import errno
import time
import sys
import os
import select
import string

myInput = './inFIFO'
try:
    if os.path.exists(myInput):
        os.unlink(myInput)
    os.mkfifo(myInput)
except Exception as e:
    sys.stderr.write("ERROR: " + str(e))
    sys.exit(2)

inFD = os.open(myInput, os.O_RDWR | os.O_NONBLOCK)
sIn = os.fdopen(inFD, 'r')

try:
    loop = 5
    while loop:
        loop = loop - 1
        readMe = select.select([sIn], [], [])[0]
        print(readMe, file = sys.stderr);
        if len(readMe):
            a = sIn.read()
            print('Message <|' + ''.join(a) + '|>', file = sys.stderr)
except Exception as e:
    sys.stderr.write('ERROR: ' + str(e))
    sys.stdin.close()
    sys.stdout.close()
    sys.stderr.close()
    os.unlink(myStdin)
    sys.exit(1)

Выход:

root:~# ./select.py &
[1] 4179
root:~# echo 'Hello World !!!' > ./inFIFO
root:~# [<_io.TextIOWrapper name=3 mode='r' encoding='UTF-8'>]
Message <|Hello World !!!
|>

root:~# echo 'Hello World !!!' > ./inFIFO
[<_io.TextIOWrapper name=3 mode='r' encoding='UTF-8'>]
Message <|Hello World !!!
|>
root:~#

Другие вопросы по теме