3

I'm quite new on python and working on a school project with this logic: Users have to answer a series of questions as fast as they can, within the given time.

For instance, the time allotted is 30 seconds, I wood loop through a dictionary of questions and get the answer. On timeout, the loop will start, even if the script is still waiting for an input.

def start_test():
    for item on questions:
        print(item)
        answers.append(input(' : '))

I've tried using multiprocessing and multithreading, but I found out that stdin doesn't work subprocesses.

I'm looking for something like:

while duration > 0:
    start_test()

def countdown():
    global duration
    while duration > 0:
        duration -= 1
        time.sleep(1)
    # something lime start_test().stop()

But I can't figure out how to run the countdown function in parallel with the start_test function.

Any ideas?

Gerard Balaoro
  • 129
  • 2
  • 13
  • Depends on your OS, one possible way is to use signal. See https://stackoverflow.com/questions/1335507/keyboard-input-with-timeout-in-python – adrtam Oct 16 '18 at 16:30
  • @AdrianTam I'm on windows, so SIGALRM is not an option. I have yet to find an alternative. Anyways, I'm also looking for a cross-platform solution. – Gerard Balaoro Oct 16 '18 at 16:35
  • 1
    You can either terminate on an input by checking the total time elapsed or you'll have to thread your script (not subprocess, thread - it's an important distinction) if you want it to bypass the input at exactly your time. – CJR Oct 16 '18 at 16:43
  • Possibly a duplicate of https://stackoverflow.com/questions/42216406/python-scheduler-vs-loop-sleep ? The question gives you two strategies for dealing with having things run for a limited time. Also look into [python scheduling](https://docs.python.org/2/library/sched.html) – Scott Mermelstein Oct 16 '18 at 16:47

1 Answers1

0

So as far as I know the input is accessible via main thread only. I might be wrong. However if that is the case, you need a non-blocking input.

Check this blog. The answer below is based on that.

Note: This is a really quick and dirty solution.

I have checked this on Linux. If it doesn't work on Windows try this link for further reference.

import _thread
import sys
import select
import time

def start_test():
        questions = ['1','2','3']
        answers = []

        for item in questions:
            print(item)

            # Input in a non-blocking way
            loop_flag = True
            while loop_flag:
                # Read documenation and examples on select
                ready =  select.select([sys.stdin], [], [], 0)[0]

                if not ready:
                    # Check if timer has expired
                    if timeout:
                        return answers
                else:
                    for file in ready:
                        line = file.readline()
                        if not line: # EOF, input is closed
                            loop_flag = False
                            break 
                        elif line.rstrip():
                            # We have some input
                            answers.append(line)
                            # So as to get out of while
                            loop_flag = False 
                            # Breaking out of for
                            break
        
        return answers
        
def countdown():
        global timeout
        time.sleep(30)
        timeout = True
    
# Global Timeout Flag
timeout = False

timer = _thread.start_new_thread(countdown, ())

answers = start_test()
print(answers)
Community
  • 1
  • 1
CodeCollector
  • 468
  • 2
  • 13