在python中创建可中断的进程

时间:2011-01-05 00:13:56

标签: python windows csv interrupt-handling

我正在创建一个解析大(但简单)CSV的python脚本。

处理需要一些时间。我希望能够中断CSV的解析,以便我可以在以后继续。

目前我有这个 - 其中有一个更大的班级:(未完成)

编辑:

我有一些更改的代码。但该系统将解析超过300万行。

def parseData(self)
    reader = csv.reader(open(self.file))
    for id, title, disc in reader:
        print "%-5s %-50s %s" % (id, title, disc)
        l = LegacyData()
        l.old_id = int(id)
        l.name = title
        l.disc_number = disc
        l.parsed = False
        l.save()

这是旧代码。

def parseData(self):
        #first line start
        fields = self.data.next()
        for row in self.data:
            items = zip(fields, row)
            item = {}
            for (name, value) in items:
                item[name] = value.strip()
            self.save(item)

谢谢你们。

4 个答案:

答案 0 :(得分:2)

如果在linux下,请按Ctrl-Z并停止正在运行的进程。输入“fg”将其恢复并从停止位置开始。

答案 1 :(得分:1)

您可以使用signal来捕获该事件。这是一个解析器的模型,可以在Windows上捕获CTRL-C并停止解析:

import signal, tme, sys

def onInterupt(signum, frame):
    raise Interupted()

try:
    #windows
    signal.signal(signal.CTRL_C_EVENT, onInterupt)
except:
    pass

class Interupted(Exception): pass
class InteruptableParser(object):

    def __init__(self, previous_parsed_lines=0):
        self.parsed_lines = previous_parsed_lines

    def _parse(self, line):
        # do stuff
        time.sleep(1) #mock up
        self.parsed_lines += 1
        print 'parsed %d' % self.parsed_lines

   def parse(self, filelike):
        for line in filelike:
            try:
                self._parse(line)
            except Interupted:
                print 'caught interupt'
                self.save()
                print 'exiting ...'
                sys.exit(0)

    def save(self):
        # do what you need to save state
        # like write the parse_lines to a file maybe
        pass

parser = InteruptableParser()
parser.parse([1,2,3])

虽然我现在在linux上,但无法测试它。

答案 2 :(得分:1)

我这样做的方式:

在一个类中使用实际的处理代码,并在该类上实现Pickle协议(http://docs.python.org/library/pickle.html)(基本上,写出正确的__getstate____setstate__函数)

此类将接受文件名,保持打开文件,并将CSV读取器实例作为实例成员。 __getstate__方法将保存当前文件位置,setstate将重新打开文件,将其转发到正确的位置,并创建一个新的阅读器。

我会用__iter__方法执行实际工作,在处理完每一行后,它会对外部函数产生影响。

这个外部函数会运行一个“主循环”监视输入中断(套接字,键盘,文件系统上特定文件的状态等等) - 一切都很安静,它只会调用下一次迭代处理器。如果发生中断,它会将处理器状态腌制到磁盘上的特定文件中。

启动时,程序只需要检查是否有保存的执行,如果是,请使用pickle检索执行程序对象,然后恢复主循环。

这里有一些(未经测试的)代码 - iea很简单:

from cPickle import load, dump
import csv
import os, sys

SAVEFILE = "running.pkl"
STOPNOWFILE = "stop.now"

class Processor(object):
    def __init__(self, filename):
        self.file = open(filename, "rt")
        self.reader = csv.reader(self.file)
    def __iter__(self):
        for line in self.reader():
            # do stuff
            yield None
    def __getstate__(self):
        return (self.file.name, self.file.tell())
    def __setstate__(self, state):
        self.file = open(state[0],"rt")
        self.file.seek(state[1])
        self.reader = csv.reader(self.File)

def check_for_interrupts():
    # Use your imagination here!  
    # One simple thing would e to check for the existence of an specific file
    # on disk.
    # But you go all the way up to instantiate a tcp server and listen to 
    # interruptions on the network
    if os.path.exists(STOPNOWFILE): 
        return True
    return False

def main():
    if os.path.exists(SAVEFILE):
        with open(SAVEFILE) as savefile:
            processor = load(savefile)
        os.unlink(savefile)
    else:
        #Assumes the name of the .csv file to be passed on the command line
        processor = Processor(sys.argv[1])
    for line in processor:
        if check_for_interrupts():
            with open(SAVEFILE, "wb") as savefile:
                dump(processor)
            break

if __name__ == "__main__":
    main()

答案 3 :(得分:0)

我的完整代码

我按照@jsbueno的建议使用了一个标志 - 但是我把它作为一个变量保存在类中,而不是另一个文件:

我创建了一个类 - 当我调用它时要求输入任何内容然后开始另一个进程来完成我的工作。因为它是循环的 - 如果我按下一个键,则设置标志并且仅在为我的下一个解析调用循环时检查。因此,我不会杀死当前的行动。 在数据库中为我正在调用的数据中的每个对象添加process标志意味着我可以随时启动它并从我离开的地方继续。

class MultithreadParsing(object):

    process = None
    process_flag = True

    def f(self):
        print "\nMultithreadParsing has started\n"
        while self.process_flag:
            ''' get my object from database '''
            legacy = LegacyData.objects.filter(parsed=False)[0:1]

            if legacy:
                print "Processing: %s %s" % (legacy[0].name, legacy[0].disc_number)
                for l in legacy:
                    ''' ... Do what I want it to do ...'''
                sleep(1)
            else:
                self.process_flag = False
                print "Nothing to parse"



    def __init__(self):
        self.process = Process(target=self.f)
        self.process.start()
        print self.process
        a = raw_input("Press any key to stop \n")
        print "\nKILL FLAG HAS BEEN SENT\n"

        if a:
            print "\nKILL\n"
            self.process_flag = False

感谢所有帮助的人(特别是你的@jsbueno) - 如果不适合你,我就不会有这个想法。