Hướng dẫn python non blocking read - python không chặn đã đọc

#!/usr/bin/env python3.5
import asyncio
import locale
import sys
from asyncio.subprocess import PIPE
from contextlib import closing

async def readline_and_kill(*args):
    # start child process
    process = await asyncio.create_subprocess_exec(*args, stdout=PIPE)

    # read line (sequence of bytes ending with b'\n') asynchronously
    async for line in process.stdout:
        print("got line:", line.decode(locale.getpreferredencoding(False)))
        break
    process.kill()
    return await process.wait() # wait for the child process to exit


if sys.platform == "win32":
    loop = asyncio.ProactorEventLoop()
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()

with closing(loop):
    sys.exit(loop.run_until_complete(readline_and_kill(
        "myprogram.exe", "arg1", "arg2")))
8,
#!/usr/bin/env python3.5
import asyncio
import locale
import sys
from asyncio.subprocess import PIPE
from contextlib import closing

async def readline_and_kill(*args):
    # start child process
    process = await asyncio.create_subprocess_exec(*args, stdout=PIPE)

    # read line (sequence of bytes ending with b'\n') asynchronously
    async for line in process.stdout:
        print("got line:", line.decode(locale.getpreferredencoding(False)))
        break
    process.kill()
    return await process.wait() # wait for the child process to exit


if sys.platform == "win32":
    loop = asyncio.ProactorEventLoop()
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()

with closing(loop):
    sys.exit(loop.run_until_complete(readline_and_kill(
        "myprogram.exe", "arg1", "arg2")))
9,
import os
import time
import subprocess

cmd = 'python3', '-c', 'import time; [(print(i), time.sleep(1)) for i in range(5)]'
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
os.set_blocking(p.stdout.fileno(), False)
start = time.time()
while True:
    # first iteration always produces empty byte string in non-blocking mode
    for i in range(2):    
        line = p.stdout.readline()
        print(i, line)
        time.sleep(0.5)
    if time.time() > start + 5:
        break
p.terminate()
0 sẽ không giúp ích trong trường hợp này.

Một cách đáng tin cậy để đọc một luồng mà không chặn bất kể hệ điều hành là sử dụng

import os
import time
import subprocess

cmd = 'python3', '-c', 'import time; [(print(i), time.sleep(1)) for i in range(5)]'
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
os.set_blocking(p.stdout.fileno(), False)
start = time.time()
while True:
    # first iteration always produces empty byte string in non-blocking mode
    for i in range(2):    
        line = p.stdout.readline()
        print(i, line)
        time.sleep(0.5)
    if time.time() > start + 5:
        break
p.terminate()
1:

import sys
from subprocess import PIPE, Popen
from threading  import Thread

try:
    from queue import Queue, Empty
except ImportError:
    from Queue import Queue, Empty  # python 2.x

ON_POSIX = 'posix' in sys.builtin_module_names

def enqueue_output(out, queue):
    for line in iter(out.readline, b''):
        queue.put(line)
    out.close()

p = Popen(['myprogram.exe'], stdout=PIPE, bufsize=1, close_fds=ON_POSIX)
q = Queue()
t = Thread(target=enqueue_output, args=(p.stdout, q))
t.daemon = True # thread dies with the program
t.start()

# ... do other things here

# read line without blocking
try:  line = q.get_nowait() # or q.get(timeout=.1)
except Empty:
    print('no output yet')
else: # got line
    # ... do something with line

Hướng dẫn python non blocking read - python không chặn đã đọc

Ankostis

7.8943 Huy hiệu vàng42 Huy hiệu bạc58 Huy hiệu Đồng3 gold badges42 silver badges58 bronze badges

Đã trả lời ngày 4 tháng 2 năm 2011 lúc 9:14Feb 4, 2011 at 9:14

47

Tôi thường có một vấn đề tương tự; Các chương trình Python tôi viết thường xuyên cần có khả năng thực hiện một số chức năng chính trong khi đồng thời chấp nhận đầu vào của người dùng từ dòng lệnh (STDIN). Chỉ cần đặt chức năng xử lý đầu vào của người dùng vào một luồng khác không giải quyết vấn đề vì

import os
import time
import subprocess

cmd = 'python3', '-c', 'import time; [(print(i), time.sleep(1)) for i in range(5)]'
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
os.set_blocking(p.stdout.fileno(), False)
start = time.time()
while True:
    # first iteration always produces empty byte string in non-blocking mode
    for i in range(2):    
        line = p.stdout.readline()
        print(i, line)
        time.sleep(0.5)
    if time.time() > start + 5:
        break
p.terminate()
2 khối và không có thời gian chờ. Nếu chức năng chính hoàn thành và không còn cần phải chờ thêm đầu vào người dùng, tôi thường muốn chương trình của mình thoát, nhưng điều đó không thể vì
import os
import time
import subprocess

cmd = 'python3', '-c', 'import time; [(print(i), time.sleep(1)) for i in range(5)]'
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
os.set_blocking(p.stdout.fileno(), False)
start = time.time()
while True:
    # first iteration always produces empty byte string in non-blocking mode
    for i in range(2):    
        line = p.stdout.readline()
        print(i, line)
        time.sleep(0.5)
    if time.time() > start + 5:
        break
p.terminate()
2 vẫn bị chặn trong luồng khác đang chờ một dòng. Một giải pháp tôi đã tìm thấy vấn đề này là biến Stdin thành một tệp không chặn bằng mô-đun FCNTL:

import fcntl
import os
import sys

# make stdin a non-blocking file
fd = sys.stdin.fileno()
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)

# user input handling thread
while mainThreadIsRunning:
      try: input = sys.stdin.readline()
      except: continue
      handleInput(input)

Theo tôi, đây là một chút sạch hơn so với sử dụng các mô -đun chọn hoặc tín hiệu để giải quyết vấn đề này nhưng sau đó, nó chỉ hoạt động trên Unix ...

Catkul

17.2K14 Huy hiệu vàng79 Huy hiệu bạc113 Huy hiệu đồng14 gold badges79 silver badges113 bronze badges

Đã trả lời ngày 27 tháng 11 năm 2009 lúc 21:33Nov 27, 2009 at 21:33

JessejesseJesse

1.08710 Huy hiệu bạc9 Huy hiệu đồng10 silver badges9 bronze badges

9

Python 3.4 Giới thiệu API tạm thời mới cho mô -đun IO -

import os
import time
import subprocess

cmd = 'python3', '-c', 'import time; [(print(i), time.sleep(1)) for i in range(5)]'
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
os.set_blocking(p.stdout.fileno(), False)
start = time.time()
while True:
    # first iteration always produces empty byte string in non-blocking mode
    for i in range(2):    
        line = p.stdout.readline()
        print(i, line)
        time.sleep(0.5)
    if time.time() > start + 5:
        break
p.terminate()
4 không đồng bộ.

Cách tiếp cận tương tự như câu trả lời dựa trên ____ 45 của @Bryan Ward-Xác định một giao thức và các phương thức của nó được gọi ngay khi dữ liệu đã sẵn sàng:

#!/usr/bin/env python3
import asyncio
import os

class SubprocessProtocol(asyncio.SubprocessProtocol):
    def pipe_data_received(self, fd, data):
        if fd == 1: # got stdout data (bytes)
            print(data)

    def connection_lost(self, exc):
        loop.stop() # end loop.run_forever()

if os.name == 'nt':
    loop = asyncio.ProactorEventLoop() # for subprocess' pipes on Windows
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(loop.subprocess_exec(SubprocessProtocol, 
        "myprogram.exe", "arg1", "arg2"))
    loop.run_forever()
finally:
    loop.close()

Xem "quy trình con" trong các tài liệu.

Có một giao diện cấp cao

import os
import time
import subprocess

cmd = 'python3', '-c', 'import time; [(print(i), time.sleep(1)) for i in range(5)]'
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
os.set_blocking(p.stdout.fileno(), False)
start = time.time()
while True:
    # first iteration always produces empty byte string in non-blocking mode
    for i in range(2):    
        line = p.stdout.readline()
        print(i, line)
        time.sleep(0.5)
    if time.time() > start + 5:
        break
p.terminate()
6 trả về các đối tượng
import os
import time
import subprocess

cmd = 'python3', '-c', 'import time; [(print(i), time.sleep(1)) for i in range(5)]'
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
os.set_blocking(p.stdout.fileno(), False)
start = time.time()
while True:
    # first iteration always produces empty byte string in non-blocking mode
    for i in range(2):    
        line = p.stdout.readline()
        print(i, line)
        time.sleep(0.5)
    if time.time() > start + 5:
        break
p.terminate()
7 cho phép đọc một dòng không đồng bộ bằng cách sử dụng
import os
import time
import subprocess

cmd = 'python3', '-c', 'import time; [(print(i), time.sleep(1)) for i in range(5)]'
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
os.set_blocking(p.stdout.fileno(), False)
start = time.time()
while True:
    # first iteration always produces empty byte string in non-blocking mode
    for i in range(2):    
        line = p.stdout.readline()
        print(i, line)
        time.sleep(0.5)
    if time.time() > start + 5:
        break
p.terminate()
8 Coroutine (với ____ 49/________ 50 Python 3.5+ Cú pháp):

#!/usr/bin/env python3.5
import asyncio
import locale
import sys
from asyncio.subprocess import PIPE
from contextlib import closing

async def readline_and_kill(*args):
    # start child process
    process = await asyncio.create_subprocess_exec(*args, stdout=PIPE)

    # read line (sequence of bytes ending with b'\n') asynchronously
    async for line in process.stdout:
        print("got line:", line.decode(locale.getpreferredencoding(False)))
        break
    process.kill()
    return await process.wait() # wait for the child process to exit


if sys.platform == "win32":
    loop = asyncio.ProactorEventLoop()
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()

with closing(loop):
    sys.exit(loop.run_until_complete(readline_and_kill(
        "myprogram.exe", "arg1", "arg2")))

1 b''
2 b'0\n'
1 b''
2 b'1\n'
1 b''
2 b'2\n'
1 b''
2 b'3\n'
1 b''
2 b'4\n'
1 thực hiện các nhiệm vụ sau:

  • bắt đầu quy trình phụ, chuyển hướng stdout của nó sang một đường ống
  • Đọc một dòng từ stdout của Sub thế giới không đồng bộ
  • Giết con trai
  • đợi nó thoát ra

Mỗi bước có thể được giới hạn bởi thời gian chờ giây nếu cần thiết.

Đã trả lời ngày 20 tháng 12 năm 2013 lúc 5:50Dec 20, 2013 at 5:50

JFSJFSjfs

385K183 Huy hiệu vàng949 Huy hiệu bạc1623 Huy hiệu Đồng183 gold badges949 silver badges1623 bronze badges

5

Trên các hệ thống giống như UNIX và Python 3.5+, có

1 b''
2 b'0\n'
1 b''
2 b'1\n'
1 b''
2 b'2\n'
1 b''
2 b'3\n'
1 b''
2 b'4\n'
2 thực hiện chính xác những gì nó nói.

import os
import time
import subprocess

cmd = 'python3', '-c', 'import time; [(print(i), time.sleep(1)) for i in range(5)]'
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
os.set_blocking(p.stdout.fileno(), False)
start = time.time()
while True:
    # first iteration always produces empty byte string in non-blocking mode
    for i in range(2):    
        line = p.stdout.readline()
        print(i, line)
        time.sleep(0.5)
    if time.time() > start + 5:
        break
p.terminate()

Điều này ra:

1 b''
2 b'0\n'
1 b''
2 b'1\n'
1 b''
2 b'2\n'
1 b''
2 b'3\n'
1 b''
2 b'4\n'

Với

1 b''
2 b'0\n'
1 b''
2 b'1\n'
1 b''
2 b'2\n'
1 b''
2 b'3\n'
1 b''
2 b'4\n'
2 nhận xét rằng đó là:

0 b'0\n'
1 b'1\n'
0 b'2\n'
1 b'3\n'
0 b'4\n'
1 b''

Đã trả lời ngày 11 tháng 12 năm 2019 lúc 17:51Dec 11, 2019 at 17:51

Saajsaajsaaj

21.5K3 Huy hiệu vàng96 Huy hiệu bạc101 Huy hiệu Đồng3 gold badges96 silver badges101 bronze badges

4

Hãy thử mô -đun AsyncProc. Ví dụ:

import os
from asyncproc import Process
myProc = Process("myprogram.app")

while True:
    # check to see if process has ended
    poll = myProc.wait(os.WNOHANG)
    if poll != None:
        break
    # print any new output
    out = myProc.read()
    if out != "":
        print out

Mô -đun chăm sóc tất cả các luồng theo đề xuất của S.Lott.

Đã trả lời ngày 13 tháng 1 năm 2009 lúc 3:36Jan 13, 2009 at 3:36

NoahnoahNoah

20.4K8 Huy hiệu vàng63 Huy hiệu bạc71 Huy hiệu đồng8 gold badges63 silver badges71 bronze badges

7

Bạn có thể làm điều này thực sự dễ dàng trong xoắn. Tùy thuộc vào cơ sở mã hiện tại của bạn, điều này có thể không dễ sử dụng, nhưng nếu bạn đang xây dựng một ứng dụng xoắn, thì những thứ như thế này trở nên gần như tầm thường. Bạn tạo một lớp

1 b''
2 b'0\n'
1 b''
2 b'1\n'
1 b''
2 b'2\n'
1 b''
2 b'3\n'
1 b''
2 b'4\n'
4 và ghi đè phương thức
1 b''
2 b'0\n'
1 b''
2 b'1\n'
1 b''
2 b'2\n'
1 b''
2 b'3\n'
1 b''
2 b'4\n'
5. Xoắn (tùy thuộc vào lò phản ứng được sử dụng) thường chỉ là một vòng
1 b''
2 b'0\n'
1 b''
2 b'1\n'
1 b''
2 b'2\n'
1 b''
2 b'3\n'
1 b''
2 b'4\n'
6 lớn với các cuộc gọi lại được cài đặt để xử lý dữ liệu từ các mô tả tệp khác nhau (thường là ổ cắm mạng). Vì vậy, phương thức
1 b''
2 b'0\n'
1 b''
2 b'1\n'
1 b''
2 b'2\n'
1 b''
2 b'3\n'
1 b''
2 b'4\n'
5 chỉ đơn giản là cài đặt một cuộc gọi lại để xử lý dữ liệu đến từ
1 b''
2 b'0\n'
1 b''
2 b'1\n'
1 b''
2 b'2\n'
1 b''
2 b'3\n'
1 b''
2 b'4\n'
8. Một ví dụ đơn giản chứng minh hành vi này như sau:

from twisted.internet import protocol, reactor

class MyProcessProtocol(protocol.ProcessProtocol):

    def outReceived(self, data):
        print data

proc = MyProcessProtocol()
reactor.spawnProcess(proc, './myprogram', ['./myprogram', 'arg1', 'arg2', 'arg3'])
reactor.run()

Các tài liệu xoắn có một số thông tin tốt về điều này.

Nếu bạn xây dựng toàn bộ ứng dụng của mình xung quanh Twisted, nó sẽ tạo ra giao tiếp không đồng bộ với các quy trình khác, cục bộ hoặc từ xa, thực sự thanh lịch như thế này. Mặt khác, nếu chương trình của bạn không được xây dựng trên đỉnh của Twisted, điều này sẽ không thực sự hữu ích. Hy vọng rằng điều này có thể hữu ích cho các độc giả khác, ngay cả khi nó không áp dụng cho ứng dụng cụ thể của bạn.

Đã trả lời ngày 21 tháng 4 năm 2011 lúc 21:54Apr 21, 2011 at 21:54

Phường Bryan WardbryanBryan Ward

6.2438 Huy hiệu vàng36 Huy hiệu bạc48 Huy hiệu đồng8 gold badges36 silver badges48 bronze badges

4

Sử dụng Chọn & Đọc (1).

import subprocess     #no new requirements
def readAllSoFar(proc, retVal=''): 
  while (select.select([proc.stdout],[],[],0)[0]!=[]):   
    retVal+=proc.stdout.read(1)
  return retVal
p = subprocess.Popen(['/bin/ls'], stdout=subprocess.PIPE)
while not p.poll():
  print (readAllSoFar(p))

Cho readline ()-như:

import fcntl
import os
import sys

# make stdin a non-blocking file
fd = sys.stdin.fileno()
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)

# user input handling thread
while mainThreadIsRunning:
      try: input = sys.stdin.readline()
      except: continue
      handleInput(input)
0

Đã trả lời ngày 26 tháng 1 năm 2011 lúc 1:02Jan 26, 2011 at 1:02

3

Mọi thứ tốt hơn rất nhiều trong Python hiện đại.

Đây là một chương trình trẻ em đơn giản, "Hello.py":

import fcntl
import os
import sys

# make stdin a non-blocking file
fd = sys.stdin.fileno()
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)

# user input handling thread
while mainThreadIsRunning:
      try: input = sys.stdin.readline()
      except: continue
      handleInput(input)
1

Và một chương trình để tương tác với nó:

import fcntl
import os
import sys

# make stdin a non-blocking file
fd = sys.stdin.fileno()
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)

# user input handling thread
while mainThreadIsRunning:
      try: input = sys.stdin.readline()
      except: continue
      handleInput(input)
2

In ra:

import fcntl
import os
import sys

# make stdin a non-blocking file
fd = sys.stdin.fileno()
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)

# user input handling thread
while mainThreadIsRunning:
      try: input = sys.stdin.readline()
      except: continue
      handleInput(input)
3

Lưu ý rằng mẫu thực tế, cũng là bởi hầu hết các câu trả lời trước đó, cả ở đây và trong các câu hỏi liên quan, là đặt bộ mô tả tệp stdout của trẻ em thành không chặn và sau đó thăm dò ý kiến ​​trong một số vòng lặp chọn. Những ngày này, tất nhiên, vòng lặp đó được cung cấp bởi Asyncio.

Đã trả lời ngày 9 tháng 5 năm 2019 lúc 2:12May 9, 2019 at 2:12

user240515user240515user240515

2.9161 Huy hiệu vàng26 Huy hiệu bạc34 Huy hiệu đồng1 gold badge26 silver badges34 bronze badges

2

Một giải pháp là thực hiện một quy trình khác để thực hiện việc đọc quy trình của bạn hoặc tạo một luồng của quy trình với thời gian chờ.

Đây là phiên bản chủ đề của hàm hết thời gian chờ:

http://code.activestate.com/recipes/473878/

Tuy nhiên, bạn có cần đọc stdout khi nó đến không? Một giải pháp khác có thể là đổ đầu ra vào một tệp và chờ quá trình hoàn thành bằng P.Wait ().p.wait().

import fcntl
import os
import sys

# make stdin a non-blocking file
fd = sys.stdin.fileno()
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)

# user input handling thread
while mainThreadIsRunning:
      try: input = sys.stdin.readline()
      except: continue
      handleInput(input)
4

Đã trả lời ngày 17 tháng 12 năm 2008 lúc 18:16Dec 17, 2008 at 18:16

Hướng dẫn python non blocking read - python không chặn đã đọc

Monkutmonkutmonkut

40.6K23 Huy hiệu vàng120 Huy hiệu bạc149 Huy hiệu đồng23 gold badges120 silver badges149 bronze badges

1

Đây là mã của tôi, được sử dụng để bắt mọi đầu ra từ quy trình con càng sớm càng tốt, bao gồm cả các dòng một phần. Nó bơm cùng một lúc và stdout và stderr theo thứ tự gần như chính xác.

Được thử nghiệm và làm việc chính xác trên Python 2.7 Linux & Windows.

import fcntl
import os
import sys

# make stdin a non-blocking file
fd = sys.stdin.fileno()
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)

# user input handling thread
while mainThreadIsRunning:
      try: input = sys.stdin.readline()
      except: continue
      handleInput(input)
5

Đã trả lời ngày 11 tháng 6 năm 2013 lúc 19:09Jun 11, 2013 at 19:09

DataCompboyDatacompboydatacompboy

3015 Huy hiệu bạc17 Huy hiệu đồng5 silver badges17 bronze badges

3

Tuyên bố miễn trừ trách nhiệm: Điều này chỉ hoạt động đối với Tornado

Bạn có thể làm điều này bằng cách đặt FD để không chặn và sau đó sử dụng IOLOOP để đăng ký gọi lại. Tôi đã đóng gói cái này trong một quả trứng có tên Tornado_SubProcess và bạn có thể cài đặt nó qua Pypi:

import fcntl
import os
import sys

# make stdin a non-blocking file
fd = sys.stdin.fileno()
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)

# user input handling thread
while mainThreadIsRunning:
      try: input = sys.stdin.readline()
      except: continue
      handleInput(input)
6

Bây giờ bạn có thể làm một cái gì đó như thế này:

import fcntl
import os
import sys

# make stdin a non-blocking file
fd = sys.stdin.fileno()
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)

# user input handling thread
while mainThreadIsRunning:
      try: input = sys.stdin.readline()
      except: continue
      handleInput(input)
7

Bạn cũng có thể sử dụng nó với RequestHandler

import fcntl
import os
import sys

# make stdin a non-blocking file
fd = sys.stdin.fileno()
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)

# user input handling thread
while mainThreadIsRunning:
      try: input = sys.stdin.readline()
      except: continue
      handleInput(input)
8

Đã trả lời ngày 6 tháng 7 năm 2012 lúc 12:42Jul 6, 2012 at 12:42

5

Các giải pháp hiện tại không hoạt động cho tôi (chi tiết bên dưới). Những gì cuối cùng đã làm việc là triển khai Readline bằng cách đọc (1) (dựa trên câu trả lời này). Cái sau không chặn:

import fcntl
import os
import sys

# make stdin a non-blocking file
fd = sys.stdin.fileno()
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)

# user input handling thread
while mainThreadIsRunning:
      try: input = sys.stdin.readline()
      except: continue
      handleInput(input)
9

Tại sao các giải pháp hiện tại không hoạt động:

  1. Các giải pháp yêu cầu Readline (bao gồm cả các hàng đợi) luôn luôn chặn. Thật khó khăn (không thể?) Để tiêu diệt chủ đề thực thi Readline. Nó chỉ bị giết khi quá trình tạo ra nó kết thúc, nhưng không phải khi quá trình sản xuất đầu ra bị giết.
  2. Trộn FCNTL cấp thấp với các cuộc gọi đọc ở cấp độ cao có thể không hoạt động đúng vì Anonnn đã chỉ ra.
  3. Sử dụng select.poll () là gọn gàng, nhưng không hoạt động trên Windows theo tài liệu Python.
  4. Sử dụng các thư viện của bên thứ ba dường như quá mức cần thiết cho nhiệm vụ này và thêm các phụ thuộc bổ sung.

Đã trả lời ngày 15 tháng 3 năm 2013 lúc 4:40Mar 15, 2013 at 4:40

Vikram Pudivikram PudiVikram Pudi

1.13710 huy hiệu bạc6 Huy hiệu đồng10 silver badges6 bronze badges

5

Tôi thêm vấn đề này để đọc một số quy trình con.popen stdout. Đây là giải pháp đọc không chặn của tôi:

#!/usr/bin/env python3
import asyncio
import os

class SubprocessProtocol(asyncio.SubprocessProtocol):
    def pipe_data_received(self, fd, data):
        if fd == 1: # got stdout data (bytes)
            print(data)

    def connection_lost(self, exc):
        loop.stop() # end loop.run_forever()

if os.name == 'nt':
    loop = asyncio.ProactorEventLoop() # for subprocess' pipes on Windows
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(loop.subprocess_exec(SubprocessProtocol, 
        "myprogram.exe", "arg1", "arg2"))
    loop.run_forever()
finally:
    loop.close()
0

Đã trả lời ngày 21 tháng 4 năm 2011 lúc 20:51Apr 21, 2011 at 20:51

2

Dưới đây là một giải pháp đơn giản dựa trên các chủ đề:

  • Hoạt động trên cả Linux và Windows (không dựa vào
    #!/usr/bin/env python3.5
    import asyncio
    import locale
    import sys
    from asyncio.subprocess import PIPE
    from contextlib import closing
    
    async def readline_and_kill(*args):
        # start child process
        process = await asyncio.create_subprocess_exec(*args, stdout=PIPE)
    
        # read line (sequence of bytes ending with b'\n') asynchronously
        async for line in process.stdout:
            print("got line:", line.decode(locale.getpreferredencoding(False)))
            break
        process.kill()
        return await process.wait() # wait for the child process to exit
    
    
    if sys.platform == "win32":
        loop = asyncio.ProactorEventLoop()
        asyncio.set_event_loop(loop)
    else:
        loop = asyncio.get_event_loop()
    
    with closing(loop):
        sys.exit(loop.run_until_complete(readline_and_kill(
            "myprogram.exe", "arg1", "arg2")))
    
    9).
  • Đọc cả
    0 b'0\n'
    1 b'1\n'
    0 b'2\n'
    1 b'3\n'
    0 b'4\n'
    1 b''
    
    0 và
    0 b'0\n'
    1 b'1\n'
    0 b'2\n'
    1 b'3\n'
    0 b'4\n'
    1 b''
    
    1 không đồng bộ.
  • Không dựa vào việc bỏ phiếu tích cực với thời gian chờ đợi tùy ý (thân thiện với CPU).
  • không sử dụng
    import os
    import time
    import subprocess
    
    cmd = 'python3', '-c', 'import time; [(print(i), time.sleep(1)) for i in range(5)]'
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
    os.set_blocking(p.stdout.fileno(), False)
    start = time.time()
    while True:
        # first iteration always produces empty byte string in non-blocking mode
        for i in range(2):    
            line = p.stdout.readline()
            print(i, line)
            time.sleep(0.5)
        if time.time() > start + 5:
            break
    p.terminate()
    
    4 (có thể mâu thuẫn với các thư viện khác).
  • Chạy cho đến khi quá trình con kết thúc.

printer.py

#!/usr/bin/env python3
import asyncio
import os

class SubprocessProtocol(asyncio.SubprocessProtocol):
    def pipe_data_received(self, fd, data):
        if fd == 1: # got stdout data (bytes)
            print(data)

    def connection_lost(self, exc):
        loop.stop() # end loop.run_forever()

if os.name == 'nt':
    loop = asyncio.ProactorEventLoop() # for subprocess' pipes on Windows
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(loop.subprocess_exec(SubprocessProtocol, 
        "myprogram.exe", "arg1", "arg2"))
    loop.run_forever()
finally:
    loop.close()
1

reader.py

#!/usr/bin/env python3
import asyncio
import os

class SubprocessProtocol(asyncio.SubprocessProtocol):
    def pipe_data_received(self, fd, data):
        if fd == 1: # got stdout data (bytes)
            print(data)

    def connection_lost(self, exc):
        loop.stop() # end loop.run_forever()

if os.name == 'nt':
    loop = asyncio.ProactorEventLoop() # for subprocess' pipes on Windows
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(loop.subprocess_exec(SubprocessProtocol, 
        "myprogram.exe", "arg1", "arg2"))
    loop.run_forever()
finally:
    loop.close()
2

Đã trả lời ngày 20 tháng 3 năm 2020 lúc 15:41Mar 20, 2020 at 15:41

2

Phiên bản đọc không chặn này không yêu cầu các mô-đun đặc biệt và sẽ hoạt động ngoài hộp trên phần lớn các bản phân phối Linux.doesn't require special modules and will work out-of-the-box on majority of Linux distros.

#!/usr/bin/env python3
import asyncio
import os

class SubprocessProtocol(asyncio.SubprocessProtocol):
    def pipe_data_received(self, fd, data):
        if fd == 1: # got stdout data (bytes)
            print(data)

    def connection_lost(self, exc):
        loop.stop() # end loop.run_forever()

if os.name == 'nt':
    loop = asyncio.ProactorEventLoop() # for subprocess' pipes on Windows
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(loop.subprocess_exec(SubprocessProtocol, 
        "myprogram.exe", "arg1", "arg2"))
    loop.run_forever()
finally:
    loop.close()
3

Đã trả lời ngày 24 tháng 5 năm 2016 lúc 15:55May 24, 2016 at 15:55

Hướng dẫn python non blocking read - python không chặn đã đọc

Tom Limetom LimeTom Lime

1.12411 Huy hiệu bạc14 Huy hiệu đồng11 silver badges14 bronze badges

Tôi có vấn đề của người hỏi ban đầu, nhưng không muốn gọi các chủ đề. Tôi đã pha trộn giải pháp của Jesse với

0 b'0\n'
1 b'1\n'
0 b'2\n'
1 b'3\n'
0 b'4\n'
1 b''
3 trực tiếp từ đường ống và trình xử lý bộ đệm của riêng tôi cho các lần đọc dòng (tuy nhiên, quá trình phụ của tôi - ping - luôn viết các dòng đầy đủ

#!/usr/bin/env python3
import asyncio
import os

class SubprocessProtocol(asyncio.SubprocessProtocol):
    def pipe_data_received(self, fd, data):
        if fd == 1: # got stdout data (bytes)
            print(data)

    def connection_lost(self, exc):
        loop.stop() # end loop.run_forever()

if os.name == 'nt':
    loop = asyncio.ProactorEventLoop() # for subprocess' pipes on Windows
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(loop.subprocess_exec(SubprocessProtocol, 
        "myprogram.exe", "arg1", "arg2"))
    loop.run_forever()
finally:
    loop.close()
4

Người theo dõi là

#!/usr/bin/env python3
import asyncio
import os

class SubprocessProtocol(asyncio.SubprocessProtocol):
    def pipe_data_received(self, fd, data):
        if fd == 1: # got stdout data (bytes)
            print(data)

    def connection_lost(self, exc):
        loop.stop() # end loop.run_forever()

if os.name == 'nt':
    loop = asyncio.ProactorEventLoop() # for subprocess' pipes on Windows
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(loop.subprocess_exec(SubprocessProtocol, 
        "myprogram.exe", "arg1", "arg2"))
    loop.run_forever()
finally:
    loop.close()
5

Và chương trình chính thiết lập một ping và sau đó gọi vòng lặp thư Gobject.

#!/usr/bin/env python3
import asyncio
import os

class SubprocessProtocol(asyncio.SubprocessProtocol):
    def pipe_data_received(self, fd, data):
        if fd == 1: # got stdout data (bytes)
            print(data)

    def connection_lost(self, exc):
        loop.stop() # end loop.run_forever()

if os.name == 'nt':
    loop = asyncio.ProactorEventLoop() # for subprocess' pipes on Windows
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(loop.subprocess_exec(SubprocessProtocol, 
        "myprogram.exe", "arg1", "arg2"))
    loop.run_forever()
finally:
    loop.close()
6

Bất kỳ công việc nào khác được gắn vào các cuộc gọi lại trong Gobject.

Hướng dẫn python non blocking read - python không chặn đã đọc

Tripleee

166K28 Huy hiệu vàng253 Huy hiệu bạc300 Huy hiệu Đồng28 gold badges253 silver badges300 bronze badges

Đã trả lời ngày 26 tháng 9 năm 2018 lúc 12:33Sep 26, 2018 at 12:33

1

Thêm câu trả lời này ở đây vì nó cung cấp khả năng đặt các đường ống không chặn trên Windows và Unix.

Tất cả các chi tiết

0 b'0\n'
1 b'1\n'
0 b'2\n'
1 b'3\n'
0 b'4\n'
1 b''
4 là nhờ câu trả lời của @techtonik.

Có một phiên bản sửa đổi một chút được sử dụng cả trên hệ thống Unix và Windows.

  • Python3 tương thích (chỉ cần thay đổi nhỏ).
  • Bao gồm phiên bản POSIX và xác định ngoại lệ để sử dụng cho một trong hai.

Bằng cách này, bạn có thể sử dụng cùng một chức năng và ngoại lệ cho mã Unix và Windows.

#!/usr/bin/env python3
import asyncio
import os

class SubprocessProtocol(asyncio.SubprocessProtocol):
    def pipe_data_received(self, fd, data):
        if fd == 1: # got stdout data (bytes)
            print(data)

    def connection_lost(self, exc):
        loop.stop() # end loop.run_forever()

if os.name == 'nt':
    loop = asyncio.ProactorEventLoop() # for subprocess' pipes on Windows
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(loop.subprocess_exec(SubprocessProtocol, 
        "myprogram.exe", "arg1", "arg2"))
    loop.run_forever()
finally:
    loop.close()
7

Để tránh đọc dữ liệu không đầy đủ, cuối cùng tôi đã viết trình tạo tuyến tính của riêng mình (trả về chuỗi byte cho mỗi dòng).

Nó là một máy phát điện để bạn có thể ví dụ ...

#!/usr/bin/env python3
import asyncio
import os

class SubprocessProtocol(asyncio.SubprocessProtocol):
    def pipe_data_received(self, fd, data):
        if fd == 1: # got stdout data (bytes)
            print(data)

    def connection_lost(self, exc):
        loop.stop() # end loop.run_forever()

if os.name == 'nt':
    loop = asyncio.ProactorEventLoop() # for subprocess' pipes on Windows
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(loop.subprocess_exec(SubprocessProtocol, 
        "myprogram.exe", "arg1", "arg2"))
    loop.run_forever()
finally:
    loop.close()
8

Đã trả lời ngày 28 tháng 1 năm 2016 lúc 3:37Jan 28, 2016 at 3:37

Hướng dẫn python non blocking read - python không chặn đã đọc

ideasman42ideasman42ideasman42

38.1K35 Huy hiệu vàng177 Huy hiệu bạc297 Huy hiệu Đồng35 gold badges177 silver badges297 bronze badges

2

Mô -đun chọn giúp bạn xác định đâu là đầu vào hữu ích tiếp theo.

Tuy nhiên, bạn hầu như luôn hạnh phúc hơn với các chủ đề riêng biệt. Một người chặn đọc Stdin, một người khác làm bất cứ nơi nào bạn không muốn bị chặn.

Đã trả lời ngày 17 tháng 12 năm 2008 lúc 18:19Dec 17, 2008 at 18:19

S.LottS.LottS.Lott

378K79 Huy hiệu vàng503 Huy hiệu bạc773 Huy hiệu Đồng79 gold badges503 silver badges773 bronze badges

3

Tại sao phải làm phiền chủ đề & hàng đợi? Không giống như readline (), BufferedReader.Read1 () sẽ không chặn chờ \ r \ n, nó trả về càng sớm càng tốt nếu có bất kỳ đầu ra nào đến.

#!/usr/bin/env python3
import asyncio
import os

class SubprocessProtocol(asyncio.SubprocessProtocol):
    def pipe_data_received(self, fd, data):
        if fd == 1: # got stdout data (bytes)
            print(data)

    def connection_lost(self, exc):
        loop.stop() # end loop.run_forever()

if os.name == 'nt':
    loop = asyncio.ProactorEventLoop() # for subprocess' pipes on Windows
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(loop.subprocess_exec(SubprocessProtocol, 
        "myprogram.exe", "arg1", "arg2"))
    loop.run_forever()
finally:
    loop.close()
9

Đã trả lời ngày 19 tháng 1 năm 2015 lúc 7:39Jan 19, 2015 at 7:39

Hướng dẫn python non blocking read - python không chặn đã đọc

2

Trong trường hợp của tôi, tôi cần một mô-đun ghi nhật ký bắt đầu đầu ra từ các ứng dụng nền và tăng cường nó (thêm dấu thời gian, màu sắc, v.v.).

Tôi đã kết thúc với một chủ đề nền thực hiện I/O thực tế. Mã sau chỉ dành cho các nền tảng POSIX. Tôi tước bỏ các bộ phận không thiết yếu.

Nếu ai đó sẽ sử dụng con thú này trong thời gian dài, hãy xem xét việc quản lý các mô tả mở. Trong trường hợp của tôi, nó không phải là một vấn đề lớn.

#!/usr/bin/env python3.5
import asyncio
import locale
import sys
from asyncio.subprocess import PIPE
from contextlib import closing

async def readline_and_kill(*args):
    # start child process
    process = await asyncio.create_subprocess_exec(*args, stdout=PIPE)

    # read line (sequence of bytes ending with b'\n') asynchronously
    async for line in process.stdout:
        print("got line:", line.decode(locale.getpreferredencoding(False)))
        break
    process.kill()
    return await process.wait() # wait for the child process to exit


if sys.platform == "win32":
    loop = asyncio.ProactorEventLoop()
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()

with closing(loop):
    sys.exit(loop.run_until_complete(readline_and_kill(
        "myprogram.exe", "arg1", "arg2")))
0

Đã trả lời ngày 1 tháng 2 năm 2015 lúc 16:32Feb 1, 2015 at 16:32

DMYTRODMYTRODmytro

4023 Huy hiệu bạc4 Huy hiệu đồng3 silver badges4 bronze badges

Vấn đề của tôi hơi khác một chút vì tôi muốn thu thập cả stdout và stderr từ một quá trình chạy, nhưng cuối cùng giống nhau vì tôi muốn hiển thị đầu ra trong một tiện ích như được tạo ra.

Tôi không muốn dùng đến nhiều cách giải quyết được đề xuất bằng cách sử dụng hàng đợi hoặc các chủ đề bổ sung vì chúng không cần thiết để thực hiện một nhiệm vụ chung như chạy tập lệnh khác và thu thập đầu ra của nó.

Sau khi đọc các giải pháp được đề xuất và tài liệu Python, tôi đã giải quyết vấn đề của mình với việc thực hiện dưới đây. Vâng, nó chỉ hoạt động cho POSIX vì tôi đang sử dụng cuộc gọi chức năng

#!/usr/bin/env python3.5
import asyncio
import locale
import sys
from asyncio.subprocess import PIPE
from contextlib import closing

async def readline_and_kill(*args):
    # start child process
    process = await asyncio.create_subprocess_exec(*args, stdout=PIPE)

    # read line (sequence of bytes ending with b'\n') asynchronously
    async for line in process.stdout:
        print("got line:", line.decode(locale.getpreferredencoding(False)))
        break
    process.kill()
    return await process.wait() # wait for the child process to exit


if sys.platform == "win32":
    loop = asyncio.ProactorEventLoop()
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()

with closing(loop):
    sys.exit(loop.run_until_complete(readline_and_kill(
        "myprogram.exe", "arg1", "arg2")))
9.

Tôi đồng ý rằng các tài liệu khó hiểu và việc thực hiện là khó xử cho một nhiệm vụ kịch bản phổ biến như vậy. Tôi tin rằng các phiên bản Python cũ hơn có mặc định khác nhau cho

0 b'0\n'
1 b'1\n'
0 b'2\n'
1 b'3\n'
0 b'4\n'
1 b''
6 và các giải thích khác nhau để tạo ra rất nhiều sự nhầm lẫn. Điều này dường như hoạt động tốt cho cả Python 2.7.12 và 3.5.2.

Điều quan trọng là đặt

0 b'0\n'
1 b'1\n'
0 b'2\n'
1 b'3\n'
0 b'4\n'
1 b''
7 cho bộ đệm dòng và sau đó
0 b'0\n'
1 b'1\n'
0 b'2\n'
1 b'3\n'
0 b'4\n'
1 b''
8 để xử lý dưới dạng tệp văn bản thay vì nhị phân dường như trở thành mặc định khi cài đặt
0 b'0\n'
1 b'1\n'
0 b'2\n'
1 b'3\n'
0 b'4\n'
1 b''
7.

#!/usr/bin/env python3.5
import asyncio
import locale
import sys
from asyncio.subprocess import PIPE
from contextlib import closing

async def readline_and_kill(*args):
    # start child process
    process = await asyncio.create_subprocess_exec(*args, stdout=PIPE)

    # read line (sequence of bytes ending with b'\n') asynchronously
    async for line in process.stdout:
        print("got line:", line.decode(locale.getpreferredencoding(False)))
        break
    process.kill()
    return await process.wait() # wait for the child process to exit


if sys.platform == "win32":
    loop = asyncio.ProactorEventLoop()
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()

with closing(loop):
    sys.exit(loop.run_until_complete(readline_and_kill(
        "myprogram.exe", "arg1", "arg2")))
1

Lỗi, gỡ lỗi và dài dòng chỉ đơn giản là các macro in đầu ra vào thiết bị đầu cuối.

Giải pháp này có hiệu quả IMHO 99,99% vì nó vẫn sử dụng chức năng chặn

import os
from asyncproc import Process
myProc = Process("myprogram.app")

while True:
    # check to see if process has ended
    poll = myProc.wait(os.WNOHANG)
    if poll != None:
        break
    # print any new output
    out = myProc.read()
    if out != "":
        print out
0, vì vậy chúng tôi giả sử quy trình phụ là tốt và đầu ra hoàn chỉnh.

Tôi hoan nghênh phản hồi để cải thiện giải pháp vì tôi vẫn còn mới với Python.

Đã trả lời ngày 27 tháng 6 năm 2017 lúc 21:45Jun 27, 2017 at 21:45

Hướng dẫn python non blocking read - python không chặn đã đọc

Brookbotbrookbotbrookbot

3011 Huy hiệu vàng2 Huy hiệu bạc10 Huy hiệu đồng1 gold badge2 silver badges10 bronze badges

2

Không phải là lần đầu tiên và có lẽ không phải là lần cuối cùng, tôi đã xây dựng một gói không chặn đường ống stdout với hai phương pháp khác nhau, một phương pháp dựa trên công việc của câu trả lời của J.F. Sebastian (@JFS), cái còn lại là một giao tiếp đơn giản ( ) Vòng lặp với một chủ đề để kiểm tra thời gian chờ.

Cả hai phương thức chụp stdout đều được kiểm tra để hoạt động cả dưới Linux và Windows, với các phiên bản Python từ 2,7 đến 3,9 kể từ thời điểm viết

Không bị chặn, nó đảm bảo thực thi thời gian chờ, ngay cả với nhiều quy trình trẻ em và cháu, và thậm chí theo Python 2.7.

Gói cũng xử lý cả byte và mã hóa stdout văn bản, là một cơn ác mộng khi cố gắng bắt EOF.

Bạn sẽ tìm thấy gói tại https://github.com/netinvent/command_runner

Nếu bạn cần một số triển khai đọc không chặn được thử nghiệm tốt, hãy thử (hoặc hack mã):

#!/usr/bin/env python3.5
import asyncio
import locale
import sys
from asyncio.subprocess import PIPE
from contextlib import closing

async def readline_and_kill(*args):
    # start child process
    process = await asyncio.create_subprocess_exec(*args, stdout=PIPE)

    # read line (sequence of bytes ending with b'\n') asynchronously
    async for line in process.stdout:
        print("got line:", line.decode(locale.getpreferredencoding(False)))
        break
    process.kill()
    return await process.wait() # wait for the child process to exit


if sys.platform == "win32":
    loop = asyncio.ProactorEventLoop()
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()

with closing(loop):
    sys.exit(loop.run_until_complete(readline_and_kill(
        "myprogram.exe", "arg1", "arg2")))
2

Bạn có thể tìm thấy mã đọc không chặn lõi trong

import os
from asyncproc import Process
myProc = Process("myprogram.app")

while True:
    # check to see if process has ended
    poll = myProc.wait(os.WNOHANG)
    if poll != None:
        break
    # print any new output
    out = myProc.read()
    if out != "":
        print out
1 hoặc
import os
from asyncproc import Process
myProc = Process("myprogram.app")

while True:
    # check to see if process has ended
    poll = myProc.wait(os.WNOHANG)
    if poll != None:
        break
    # print any new output
    out = myProc.read()
    if out != "":
        print out
2 tùy thuộc vào phương thức chụp được sử dụng. Từ đó, bạn có thể hack theo cách của bạn đến những gì bạn muốn hoặc chỉ sử dụng toàn bộ gói để thực thi các lệnh của bạn như một sự thay thế quy trình phụ.

Đã trả lời ngày 8 tháng 9 năm 2021 lúc 9:03Sep 8, 2021 at 9:03

Orsiris de Jongorsiris de JongOrsiris de Jong

2.5201 Huy hiệu vàng23 Huy hiệu bạc43 Huy hiệu đồng1 gold badge23 silver badges43 bronze badges

Đã trả lời ngày 27 tháng 4 năm 2013 lúc 20:14Apr 27, 2013 at 20:14

Cenk Alticenk AltiCenk Alti

2.7312 huy hiệu vàng24 Huy hiệu bạc25 Huy hiệu đồng2 gold badges24 silver badges25 bronze badges

0

Làm việc từ câu trả lời của J.F. Sebastian và một số nguồn khác, tôi đã tập hợp một người quản lý quy trình phụ đơn giản. Nó cung cấp yêu cầu đọc không chặn, cũng như chạy một số quy trình song song. Nó không sử dụng bất kỳ cuộc gọi dành riêng cho hệ điều hành nào (mà tôi biết) và do đó sẽ hoạt động ở bất cứ đâu.

Nó có sẵn từ PYPI, vì vậy chỉ

import os
from asyncproc import Process
myProc = Process("myprogram.app")

while True:
    # check to see if process has ended
    poll = myProc.wait(os.WNOHANG)
    if poll != None:
        break
    # print any new output
    out = myProc.read()
    if out != "":
        print out
3. Tham khảo trang dự án để biết ví dụ và tài liệu đầy đủ.

Đã trả lời ngày 31 tháng 10 năm 2013 lúc 10:09Oct 31, 2013 at 10:09

eda-qa mort-ora-yeda-qa mort-or-yedA-qa mort-ora-y

29.1K38 Huy hiệu vàng132 Huy hiệu bạc254 Huy hiệu đồng38 gold badges132 silver badges254 bronze badges

Chỉnh sửa: Việc triển khai này vẫn chặn. Thay vào đó, hãy sử dụng câu trả lời của J.F.Sebastian.

Tôi đã thử câu trả lời hàng đầu, nhưng rủi ro bổ sung và duy trì mã luồng là đáng lo ngại.

Nhìn qua mô -đun IO (và được giới hạn ở 2.6), tôi tìm thấy BufferedReader. Đây là giải pháp không chặn, không chặn của tôi.

#!/usr/bin/env python3.5
import asyncio
import locale
import sys
from asyncio.subprocess import PIPE
from contextlib import closing

async def readline_and_kill(*args):
    # start child process
    process = await asyncio.create_subprocess_exec(*args, stdout=PIPE)

    # read line (sequence of bytes ending with b'\n') asynchronously
    async for line in process.stdout:
        print("got line:", line.decode(locale.getpreferredencoding(False)))
        break
    process.kill()
    return await process.wait() # wait for the child process to exit


if sys.platform == "win32":
    loop = asyncio.ProactorEventLoop()
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()

with closing(loop):
    sys.exit(loop.run_until_complete(readline_and_kill(
        "myprogram.exe", "arg1", "arg2")))
3

Đã trả lời ngày 7 tháng 5 năm 2013 lúc 17:38May 7, 2013 at 17:38

Romcromcromc

695 huy hiệu đồng5 bronze badges

2

Đây là một ví dụ để chạy lệnh tương tác trong quy trình con và stdout có tính tương tác bằng cách sử dụng thiết bị đầu cuối giả. Bạn có thể tham khảo: https://stackoverflow.com/a/43012138/3555925

#!/usr/bin/env python3.5
import asyncio
import locale
import sys
from asyncio.subprocess import PIPE
from contextlib import closing

async def readline_and_kill(*args):
    # start child process
    process = await asyncio.create_subprocess_exec(*args, stdout=PIPE)

    # read line (sequence of bytes ending with b'\n') asynchronously
    async for line in process.stdout:
        print("got line:", line.decode(locale.getpreferredencoding(False)))
        break
    process.kill()
    return await process.wait() # wait for the child process to exit


if sys.platform == "win32":
    loop = asyncio.ProactorEventLoop()
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()

with closing(loop):
    sys.exit(loop.run_until_complete(readline_and_kill(
        "myprogram.exe", "arg1", "arg2")))
4

Đã trả lời ngày 25 tháng 3 năm 2017 lúc 3:40Mar 25, 2017 at 3:40

PacopacoPaco

3612 Huy hiệu bạc9 Huy hiệu Đồng2 silver badges9 bronze badges

Giải pháp này sử dụng mô -đun

#!/usr/bin/env python3.5
import asyncio
import locale
import sys
from asyncio.subprocess import PIPE
from contextlib import closing

async def readline_and_kill(*args):
    # start child process
    process = await asyncio.create_subprocess_exec(*args, stdout=PIPE)

    # read line (sequence of bytes ending with b'\n') asynchronously
    async for line in process.stdout:
        print("got line:", line.decode(locale.getpreferredencoding(False)))
        break
    process.kill()
    return await process.wait() # wait for the child process to exit


if sys.platform == "win32":
    loop = asyncio.ProactorEventLoop()
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()

with closing(loop):
    sys.exit(loop.run_until_complete(readline_and_kill(
        "myprogram.exe", "arg1", "arg2")))
9 để "đọc bất kỳ dữ liệu có sẵn nào" từ luồng IO. Hàm này chặn ban đầu cho đến khi dữ liệu có sẵn, nhưng sau đó chỉ đọc dữ liệu có sẵn và không chặn thêm.

Với thực tế là nó sử dụng mô -đun

#!/usr/bin/env python3.5
import asyncio
import locale
import sys
from asyncio.subprocess import PIPE
from contextlib import closing

async def readline_and_kill(*args):
    # start child process
    process = await asyncio.create_subprocess_exec(*args, stdout=PIPE)

    # read line (sequence of bytes ending with b'\n') asynchronously
    async for line in process.stdout:
        print("got line:", line.decode(locale.getpreferredencoding(False)))
        break
    process.kill()
    return await process.wait() # wait for the child process to exit


if sys.platform == "win32":
    loop = asyncio.ProactorEventLoop()
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()

with closing(loop):
    sys.exit(loop.run_until_complete(readline_and_kill(
        "myprogram.exe", "arg1", "arg2")))
9, điều này chỉ hoạt động trên Unix.

Mã hoàn toàn tuân thủ PEP8.

#!/usr/bin/env python3.5
import asyncio
import locale
import sys
from asyncio.subprocess import PIPE
from contextlib import closing

async def readline_and_kill(*args):
    # start child process
    process = await asyncio.create_subprocess_exec(*args, stdout=PIPE)

    # read line (sequence of bytes ending with b'\n') asynchronously
    async for line in process.stdout:
        print("got line:", line.decode(locale.getpreferredencoding(False)))
        break
    process.kill()
    return await process.wait() # wait for the child process to exit


if sys.platform == "win32":
    loop = asyncio.ProactorEventLoop()
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()

with closing(loop):
    sys.exit(loop.run_until_complete(readline_and_kill(
        "myprogram.exe", "arg1", "arg2")))
5

Đã trả lời ngày 2 tháng 10 năm 2017 lúc 20:55Oct 2, 2017 at 20:55

Bradley Odellbradley OdellBradley Odell

1.2282 Huy hiệu vàng15 Huy hiệu bạc27 Huy hiệu đồng2 gold badges15 silver badges27 bronze badges

Tôi cũng phải đối mặt với vấn đề được mô tả bởi Jesse và giải quyết nó bằng cách sử dụng "Chọn" làm Bradley, Andy và những người khác đã làm nhưng trong một chế độ chặn để tránh một vòng lặp bận rộn. Nó sử dụng một ống giả như một stdin giả. Các khối chọn và chờ stdin hoặc đường ống đã sẵn sàng. Khi một khóa được nhấn stdin bỏ chặn, giá trị chọn và giá trị khóa có thể được lấy bằng đọc (1). Khi một luồng khác ghi vào đường ống thì đường ống bỏ chặn sự lựa chọn và nó có thể được coi là một dấu hiệu cho thấy sự cần thiết của stdin đã kết thúc. Đây là một số mã tham chiếu:

#!/usr/bin/env python3.5
import asyncio
import locale
import sys
from asyncio.subprocess import PIPE
from contextlib import closing

async def readline_and_kill(*args):
    # start child process
    process = await asyncio.create_subprocess_exec(*args, stdout=PIPE)

    # read line (sequence of bytes ending with b'\n') asynchronously
    async for line in process.stdout:
        print("got line:", line.decode(locale.getpreferredencoding(False)))
        break
    process.kill()
    return await process.wait() # wait for the child process to exit


if sys.platform == "win32":
    loop = asyncio.ProactorEventLoop()
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()

with closing(loop):
    sys.exit(loop.run_until_complete(readline_and_kill(
        "myprogram.exe", "arg1", "arg2")))
6

Đã trả lời ngày 7 tháng 4 năm 2018 lúc 7:54Apr 7, 2018 at 7:54

1

Hãy thử WEXPECT, đó là phương án thay thế Windows của pexpect.

#!/usr/bin/env python3.5
import asyncio
import locale
import sys
from asyncio.subprocess import PIPE
from contextlib import closing

async def readline_and_kill(*args):
    # start child process
    process = await asyncio.create_subprocess_exec(*args, stdout=PIPE)

    # read line (sequence of bytes ending with b'\n') asynchronously
    async for line in process.stdout:
        print("got line:", line.decode(locale.getpreferredencoding(False)))
        break
    process.kill()
    return await process.wait() # wait for the child process to exit


if sys.platform == "win32":
    loop = asyncio.ProactorEventLoop()
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()

with closing(loop):
    sys.exit(loop.run_until_complete(readline_and_kill(
        "myprogram.exe", "arg1", "arg2")))
7

Đã trả lời ngày 7 tháng 12 năm 2019 lúc 14:13Dec 7, 2019 at 14:13

Betontalpfabetontalpfabetontalpfa

3,2041 Huy hiệu vàng32 Huy hiệu bạc57 Huy hiệu đồng1 gold badge32 silver badges57 bronze badges

Dưới đây là một mô-đun hỗ trợ các lần đọc không chặn và ghi nền bằng Python:

https://pypi.python.org/pypi/python-nonblock

Cung cấp một chức năng,

Nonlock_read sẽ đọc dữ liệu từ luồng, nếu có, nếu không hãy trả về một chuỗi trống (hoặc không có nếu luồng được đóng ở phía bên kia và tất cả các dữ liệu có thể đã được đọc)

Bạn cũng có thể xem xét mô-đun Python-subprocess2,

https://pypi.python.org/pypi/python-subprocess2

trong đó thêm vào mô -đun phụ. Vì vậy, trên đối tượng được trả về từ "Subprocess.popen" được thêm vào một phương thức bổ sung, RuninBackground. Điều này bắt đầu một luồng và trả về một đối tượng sẽ tự động được điền vì nội dung được viết vào stdout/stderr, mà không chặn luồng chính của bạn.

Enjoy!

Đã trả lời ngày 16 tháng 1 năm 2016 lúc 21:47Jan 16, 2016 at 21:47

Hướng dẫn python non blocking read - python không chặn đã đọc

1