Python freezes in a While Loop

1

Using a while loop, I throw a command in cmd (windows), which repeats every 60 seconds. At a certain moment, the script that I launched per cmd freezes and the loop is locked. How can the python script interrupt and automatically start the while without importing the status of the cmd?

This would be the code I'm using

# Import time for sleep
import datetime
import time
import os

count = 0

while(True):

    os.system('...')

    # Fecha
    now = datetime.datetime.now()
    fecha = now.strftime("%d-%m-%Y %H:%M:%S")

    print(fecha + " / Descarga: %d" % (count + 1))
    count += 1

    time.sleep(60)

UPDATE N1

The problem now is the arguments. First I pass the code of the .py and then a capture of the errors caused by the cmd.

import datetime
import subprocess
import time

d_token = "ewifjweof87ew98f7we"
d_channel = "9809808"
d_date = time.strftime("%d/%m/%Y") ## dd/mm/yyyy format
d_format = "PlainText"
cmd = ["DiscordChatExporter.Cli.exe", "-t", d_token, "-c", d_channel, "-o", "logs-gocrypto.txt", "--datefrom", d_date, "-f", d_format]

timeout = 60

count = 0
while True:
    t0 = time.perf_counter()
    try:
        subprocess.run(cmd, check=True, timeout=timeout, shell=True)
        now = datetime.datetime.now()
        fecha = now.strftime("%d-%m-%Y %H:%M:%S")
        print("{} / Descarga: {}".format(fecha, count + 1))    
        count += 1

    except subprocess.TimeoutExpired:
        print("[ERROR] Proceso terminado tras timeout")

    except subprocess.CalledProcessError:
        print("[ERROR] El proceso no termino correctamente")

    finally:
        t_restante = timeout - (time.perf_counter() - t0)
        if t_restante > 0:
            time.sleep(t_restante)

The error in CMD

    
asked by tomillo 26.04.2018 в 23:17
source

1 answer

1

The problem is that os.system calls the process and is waiting for it to end , which stops your code at this point indefinitely, without being able to delay or kill the process.

First of all, you should use the module subprocess instead of os.system , which is considered in practice " deprecated " in modern versions of Python and for your purposes is too rudimentary. subprocess will allow you much more control over the process; direct communication with the process during execution (passing commands and receiving responses), redirecting dtdin , stdout and stderr , sending signals of completion, checking the status of the process and its output, timeouts, etc.

That said, and assuming you use Python 3, you can do the following:

  • If you want the script to launch the process, wait for its completion and immediately launch another when it finishes , killing the previous one if it has not finished after 60 seconds, you can use subprocess.run or subproces.check_call with timeout :

    import datetime
    import subprocess
    
    cmd = "tu_comando"
    timeout = 60
    
    count = 0
    while True:
        try:
            subprocess.run(cmd, timeout=timeout, check=True)
            now = datetime.datetime.now()
            fecha = now.strftime("%d-%m-%Y %H:%M:%S")
            print("{} / Descarga: {}".format(fecha, count + 1))    
            count += 1
    
        except subprocess.TimeoutExpired:
            print("[ERROR] Proceso terminado tras timeout")
    
        except subprocess.CalledProcessError:
            print("[ERROR] El proceso no termino correctamente")
    
  • If you want to launch the process every 60 seconds always, forcing its termination if it is still alive after that time, you can also use subprocess.run but with a small modification to wait the remaining time if the process ends before 60 seconds:

    import datetime
    import subprocess
    import time
    
    cmd = "tu_proceso"
    timeout = 60
    
    count = 0
    while True:
        t0 = time.perf_counter()
        try:
            subprocess.run(cmd, check=True, timeout=timeout)
            now = datetime.datetime.now()
            fecha = now.strftime("%d-%m-%Y %H:%M:%S")
            print("{} / Descarga: {}".format(fecha, count + 1))    
            count += 1
    
        except subprocess.TimeoutExpired:
            print("[ERROR] Proceso terminado tras timeout")
    
        except subprocess.CalledProcessError:
            print("[ERROR] El proceso no termino correctamente")
    
        finally:
            t_restante = timeout - (time.perf_counter() - t0)
            if t_restante > 0:
                time.sleep(t_restante)
    

If your command is a buit-in of the terminal itself (such as mkdir , dir , copy , etc) you need to pass the argument shell=True to subprocess.run , for the rest of cases not it is neither necessary nor recommended (for example to execute a batch file).

  

Note: If you wish you can redirect stdout and stderr to get the standard output of the process in the Python script.

    
answered by 27.04.2018 / 01:57
source