python threading.timer在程序运行时间时设置时间限制

SXC*_*C88 2 python multithreading timeout timer

我有一些与在Python中设置函数的最大运行时间相关的问题.实际上,我想pdfminer用来将.pdf文件转换为.txt.

问题是,很多时候,某些文件无法解码并且需要很长时间.所以我想设置threading.Timer()为将每个文件的转换时间限制为5秒.另外,我在windows下运行,所以我不能使用这个signal模块.

我成功运行了转换代码pdfminer.convert_pdf_to_txt()(在我的代码中是" c"),但我不确定以下代码中是否threading.Timer()有效.(我认为这不会限制每次处理的时间)

总之,我想:

  1. 将pdf转换为txt

  2. 每次转换的时间限制为5秒,如果超时,则抛出异常并保存空文件

  3. 将所有txt文件保存在同一文件夹下

  4. 如果有任何异常/错误,仍然保存文件但内容为空.

这是当前的代码:

import converter as c
import os
import timeit
import time
import threading
import thread

yourpath = 'D:/hh/'

def iftimesout():
    print("no")

    with open("D:/f/"+g+"&"+t+"&"+name+".txt", mode="w") as newfile:
        newfile.write("")


for root, dirs, files in os.walk(yourpath, topdown=False):
    for name in files:
        try:
           timer = threading.Timer(5.0,iftimesout)
           timer.start()
           t=os.path.split(os.path.dirname(os.path.join(root, name)))[1]
           a=str(os.path.split(os.path.dirname(os.path.join(root, name)))[0])
           g=str(a.split("\\")[1])

           with open("D:/f/"+g+"&"+t+"&"+name+".txt", mode="w") as newfile:
                newfile.write(c.convert_pdf_to_txt(os.path.join(root, name)))
                print("yes")

           timer.cancel()

         except KeyboardInterrupt:
               raise

         except:
             for name in files:
                 t=os.path.split(os.path.dirname(os.path.join(root, name)))[1]
                 a=str(os.path.split(os.path.dirname(os.path.join(root, name)))[0])

                 g=str(a.split("\\")[1])
                 with open("D:/f/"+g+"&"+t+"&"+name+".txt", mode="w") as newfile:
                     newfile.write("") 
Run Code Online (Sandbox Code Playgroud)

lin*_*usg 5

我终于想通了!

首先,定义一个函数来调用具有有限超时的另一个函数:

import multiprocessing

def call_timeout(timeout, func, args=(), kwargs={}):
    if type(timeout) not in [int, float] or timeout <= 0.0:
        print("Invalid timeout!")

    elif not callable(func):
        print("{} is not callable!".format(type(func)))

    else:
        p = multiprocessing.Process(target=func, args=args, kwargs=kwargs)
        p.start()
        p.join(timeout)

        if p.is_alive():
            p.terminate()
            return False
        else:
            return True
Run Code Online (Sandbox Code Playgroud)

这个功能有什么作用?

  • 检查超时和功能是否有效
  • 在新进程中启动给定函数,这比线程有一些优势
  • 将程序阻塞x秒(p.join())并允许在此时执行该功能
  • 超时到期后,检查该功能是否仍在运行

    • 是的:终止并返回 False
    • 不:很好,没有超时!返回True

我们可以测试它time.sleep():

import time

finished = call_timeout(2, time.sleep, args=(1, ))
if finished:
    print("No timeout")
else:
    print("Timeout")
Run Code Online (Sandbox Code Playgroud)

我们运行一个需要一秒钟完成的功能,超时设置为两秒:

No timeout
Run Code Online (Sandbox Code Playgroud)

如果我们运行time.sleep(10)并将超时设置为两秒:

finished = call_timeout(2, time.sleep, args=(10, ))
Run Code Online (Sandbox Code Playgroud)

结果:

Timeout
Run Code Online (Sandbox Code Playgroud)

请注意,程序在两秒钟后停止,而不完成被调用的功能.

您的最终代码如下所示:

import converter as c
import os
import timeit
import time
import multiprocessing

yourpath = 'D:/hh/'

def call_timeout(timeout, func, args=(), kwargs={}):
    if type(timeout) not in [int, float] or timeout <= 0.0:
        print("Invalid timeout!")

    elif not callable(func):
        print("{} is not callable!".format(type(func)))

    else:
        p = multiprocessing.Process(target=func, args=args, kwargs=kwargs)
        p.start()
        p.join(timeout)

        if p.is_alive():
            p.terminate()
            return False
        else:
            return True

def convert(root, name, g, t):
    with open("D:/f/"+g+"&"+t+"&"+name+".txt", mode="w") as newfile:
        newfile.write(c.convert_pdf_to_txt(os.path.join(root, name)))

for root, dirs, files in os.walk(yourpath, topdown=False):
    for name in files:
        try:
           t=os.path.split(os.path.dirname(os.path.join(root, name)))[1]
           a=str(os.path.split(os.path.dirname(os.path.join(root, name)))[0])
           g=str(a.split("\\")[1])
           finished = call_timeout(5, convert, args=(root, name, g, t))

           if finished:
               print("yes")
           else:
               print("no")

               with open("D:/f/"+g+"&"+t+"&"+name+".txt", mode="w") as newfile:
                   newfile.write("")

        except KeyboardInterrupt:
             raise

       except:
           for name in files:
                t=os.path.split(os.path.dirname(os.path.join(root, name)))[1]
                a=str(os.path.split(os.path.dirname(os.path.join(root, name)))[0])

               g=str(a.split("\\")[1])
               with open("D:/f/"+g+"&"+t+"&"+name+".txt", mode="w") as newfile:
                   newfile.write("") 
Run Code Online (Sandbox Code Playgroud)

代码应该易于理解,如果没有,请随意询问.

我真的希望这会有所帮助(因为我们花了一些时间才能把它弄好;))!