Синхронизированный ввод Python

Oct 14 2020

Я пишу игрового бота на Python, где пользователю необходимо отправить ввод в течение определенного времени.

Моя текущая реализация этого состоит в том, чтобы создать новый поток, который спит в течение этого времени, а затем проверяет, был ли отправлен ввод. Одноразовый номер добавляется, поскольку время может истечь после запуска другого потока, что приведет к тому, что if chatid in user_threadsчасть будет оцениваться как истинная. Должен ли я использовать этот метод или есть лучшее решение для ввода по времени (в том смысле, что с меньшей вероятностью произойдет сбой из-за подобных условий гонки).

Я также пробовал использовать, multiprocessing.Processно совместное использование переменных другому процессу кажется намного более громоздким.

from threading import Thread
from time import time, sleep
from random import randint

user_threads = {}

def timeout(t,r):
    while time()-t<5:
        sleep(5-time()+t)
    if chatid in user_threads:
        if user_threads[chatid][3] != r:
            return
        del user_threads[chatid]
        print("Too slow")

def recvans(ans,inp):
    if ans==inp:
        print("yes")
    else:
        print("no")

def starttimer(chatid):
    r = randint(0,1<<128)
    user_threads[chatid] = [None,None,None,r]
    user_threads[chatid][2] = ["a"]
    P = Thread(target = timeout, args = (time(),r))
    user_threads[chatid][0] = P
    user_threads[chatid][1] = recvans
    P.start()

while True: # simulating user input from different users (here chatid=1)
    inp = input()
    chatid = 1
    if chatid in user_threads:
        t, func, args, _ = user_threads[chatid]
        if t == None:
            print("Please wait")
            continue
        del user_threads[chatid]
        args += [inp]
        func(*args)
        continue
    if inp == "Start":
        starttimer(chatid)
        continue
    if inp == "Quit":
        break
    print("Unknown msg")

Ответы

2 Reinderien Oct 14 2020 at 00:41

Что сказал @vnp. В корне,

  • inputиспользует stdin;
  • stdin может интерпретироваться как дескриптор файла, пока вы не в Windows;
  • select может дождаться доступности данных на таких ручках.

По этой теме есть много справочной информации в Интернете, в том числе https://stackoverflow.com/a/3471853/313768; процитировать решение там:

import sys 
from select import select

timeout = 10 
print "Enter something:", 
rlist, _, _ = select([sys.stdin], [], [], timeout) 
if rlist:
    s = sys.stdin.readline()
    print s 
else:
    print "No input. Moving on..."