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

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ờ:

//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

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

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 đủ

Bài Viết Liên Quan

Chủ Đề