pythonstdin_关于python:从sys.stdin接收输入,非阻塞

我正在为比赛制作机器人,该机器人通过sys.stdin接收其输入,并使用Python的print()作为输出。 我有以下内容:

1

2

3

4

5

6

7

8import sys

def main():

while True:

line = sys.stdin.readline()

parts = line.split()

if len(parts) > 0:

# do stuff

问题在于输入是通过流输入的,并且使用上述输入,使我无法打印任何内容,直到关闭流。 我该怎么做才能使这项工作?

也许重复

在stdin上进行非阻塞要么不起作用,要么不十分可靠。 是否允许使用线程/多处理? 应该起作用的原因

通过关闭阻止功能,您一次只能读取一个字符。因此,没有办法让readline()在非阻塞上下文中工作。我假设您只是想阅读按键来控制机器人。

我在Linux上使用select.select()并没有运气,并通过调整termios设置创建了一种方法。因此,这是特定于Linux的,但对我有用:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32old_settings=None

def init_anykey():

global old_settings

old_settings = termios.tcgetattr(sys.stdin)

new_settings = termios.tcgetattr(sys.stdin)

new_settings[3] = new_settings[3] & ~(termios.ECHO | termios.ICANON) # lflags

new_settings[6][termios.VMIN] = 0 # cc

new_settings[6][termios.VTIME] = 0 # cc

termios.tcsetattr(sys.stdin, termios.TCSADRAIN, new_settings)

@atexit.register

def term_anykey():

global old_settings

if old_settings:

termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)

def anykey():

ch_set = []

ch = os.read(sys.stdin.fileno(), 1)

while ch != None and len(ch) > 0:

ch_set.append( ord(ch[0]) )

ch = os.read(sys.stdin.fileno(), 1)

return ch_set;

init_anykey()

while True:

key = anykey()

if key != None:

print key

else:

time.sleep(0.1)

更好的Windows或跨平台答案在这里:Python非阻塞控制台输入

请注意,这也会使终端"不回声":未显示按键。 这是实现此目的的另一种优雅方式:ballingt.com/nonblocking-stdin-in-python-3

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20#-----------------------------------------------------------------------

# Get a character from the keyboard. If Block is True wait for input,

# else return any available character or throw an exception if none is

# available. Ctrl+C isn't handled and continues to generate the usual

# SIGINT signal, but special keys like the arrows return the expected

# escape sequences.

#

# This requires:

#

# import sys, select

#

# This was tested using python 2.7 on Mac OS X. It will work on any

# Linux system, but will likely fail on Windows due to select/stdin

# limitations.

#-----------------------------------------------------------------------

def GetChar(Block=True):

if Block or select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], []):

return sys.stdin.read(1)

raise error('NoChar')

我相信我曾经在Linux上尝试过,但我认为它没有用。 但是,在Mac上我现在正在使用,它绝对不起作用。 无论block是true还是false,它仍然会阻塞。 此外,用户必须按Enter键才能释放积累的字符"泛滥"。 也许尝试将输入模式设置为raw(tty.setraw()),但是之后必须将其设置为煮熟模式。

您可以使用选择器来处理I / O多路复用:

https://docs.python.org/3/library/selectors.html

试试看:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25#! /usr/bin/python3

import sys

import fcntl

import os

import selectors

# set sys.stdin non-blocking

orig_fl = fcntl.fcntl(sys.stdin, fcntl.F_GETFL)

fcntl.fcntl(sys.stdin, fcntl.F_SETFL, orig_fl | os.O_NONBLOCK)

# function to be called when enter is pressed

def got_keyboard_data(stdin):

print('Keyboard input: {}'.format(stdin.read()))

# register event

m_selector = selectors.DefaultSelector()

m_selector.register(sys.stdin, selectors.EVENT_READ, got_keyboard_data)

while True:

sys.stdout.write('Type something and hit enter: ')

sys.stdout.flush()

for k, mask in m_selector.select():

callback = k.data

callback(k.fileobj)

上面的代码将保留

1for k, mask in m_selector.select():

直到发生注册的事件为止,返回选择器(key)实例(k)和受监视事件的掩码。

在上面的示例中,我们仅注册了一个事件(按Enter键):

1m_selector.register(sys.stdin, selectors.EVENT_READ, got_keyboard_data)

选择器键实例定义如下:

1abstractmethod register(fileobj, events, data=None)

因此,register方法将k.data设置为我们的回调函数got_keyboard_data,并在按下Enter键时调用它:

1

2callback = k.data

callback(k.fileobj)

一个更完整的示例(希望更有用)是将来自用户的标准输入数据与来自网络的传入连接进行复用:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76import selectors

import socket

import sys

import os

import fcntl

m_selector = selectors.DefaultSelector()

# set sys.stdin non-blocking

def set_input_nonblocking():

orig_fl = fcntl.fcntl(sys.stdin, fcntl.F_GETFL)

fcntl.fcntl(sys.stdin, fcntl.F_SETFL, orig_fl | os.O_NONBLOCK)

def create_socket(port, max_conn):

server_addr = ('localhost', port)

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

server.setblocking(False)

server.bind(server_addr)

server.listen(max_conn)

return server

def read(conn, mask):

global GO_ON

client_address = conn.getpeername()

data = conn.recv(1024)

print('Got {} from {}'.format(data, client_address))

if not data:

GO_ON = False

def accept(sock, mask):

new_conn, addr = sock.accept()

new_conn.setblocking(False)

print('Accepting connection from {}'.format(addr))

m_selector.register(new_conn, selectors.EVENT_READ, read)

def quit():

global GO_ON

print('Exiting...')

GO_ON = False

def from_keyboard(arg1, arg2):

line = arg1.read()

if line == 'quit

':

quit()

else:

print('User input: {}'.format(line))

GO_ON = True

set_input_nonblocking()

# listen to port 10000, at most 10 connections

server = create_socket(10000, 10)

m_selector.register(server, selectors.EVENT_READ, accept)

m_selector.register(sys.stdin, selectors.EVENT_READ, from_keyboard)

while GO_ON:

sys.stdout.write('>>> ')

sys.stdout.flush()

for k, mask in m_selector.select():

callback = k.data

callback(k.fileobj, mask)

# unregister events

m_selector.unregister(sys.stdin)

# close connection

server.shutdown()

server.close()

# close select

m_selector.close()

您可以使用两个终端进行测试。

第一航站楼:

1

2$ python3 test.py

>>> bla

打开另一个终端并运行:

1

2$ nc localhost 10000

hey!

回到第一

1>>> qwerqwer

结果(在主终端上看到):

1

2

3

4

5

6

7

8

9

10

11$ python3 test.py

>>> bla

User input: bla

>>> Accepting connection from ('127.0.0.1', 39598)

>>> Got b'hey!

' from ('127.0.0.1', 39598)

>>> qwerqwer

User input: qwerqwer

>>>

请在您的帖子中添加说明,以便将来的访问者清楚易懂

我可以建议nobreak吗?如果不是,您愿意使用诅咒。

https://docs.python.org/3/library/curses.html#curses.window.nodelay

使用发电机-幸运的是sys.stdin已经是发电机!

生成器使您可以处理无限流。始终在调用它时会返回下一个元素。为了构建生成器,您需要yield关键字。

1

2

3

4

5for line in sys.stdin:

print line

if a_certain_situation_happens:

break

如果发生某些希望的情况,请不要忘记在循环中放置break语句。

您可以在以下位置找到有关生成器的更多信息:

http://www.dabeaz.com/generators/index.html

http://linuxgazette.net/100/pramode.html

阿伦特还有其他因素在起作用吗? 例如流是行缓冲还是块缓冲?

sys.stdin已经是一个生成器,因此您可以执行for line in sys.stdin: ...或使用更新的fileinput模块。 两者都不是非阻塞的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值