Entrada temporizada de Python

Oct 14 2020

Estoy escribiendo un juego-bot de Python donde un usuario necesita enviar una entrada dentro de una cierta cantidad de tiempo.

Mi implementación actual de esto es generar un nuevo hilo que duerme durante esa cantidad de tiempo, luego verifica si se ha enviado una entrada. Se agrega un nonce ya que el tiempo podría agotarse después de que comience otro hilo, lo que haría que la if chatid in user_threadsparte se evalúe como verdadera. ¿Debo usar este método o hay una mejor solución para tener una entrada cronometrada (en el sentido de que es menos probable que falle debido a condiciones de carrera similares)?

También intenté usar, multiprocessing.Processpero compartir variables con el otro proceso parece ser mucho más engorroso.

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")

Respuestas

2 Reinderien Oct 14 2020 at 00:41

Lo que dijo @vnp. Fundamentalmente,

  • inputusos stdin;
  • stdin se puede interpretar como un identificador de archivo siempre que no esté en Windows;
  • select puede esperar la disponibilidad de datos en dichos identificadores.

Hay mucha ayuda en Internet sobre este tema, que incluye https://stackoverflow.com/a/3471853/313768; para citar la solución allí:

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..."