代码之家  ›  专栏  ›  技术社区  ›  Timothy Wong

Python线程和代码的一般问题

  •  0
  • Timothy Wong  · 技术社区  · 9 年前

    给定以下Python3代码和线程:

    class main:
        def __init__(self):
            self.text = open(os.getcwd()+"/FileScanLogs.txt", "a+")
            self.hashlist = queue.Queue()
            self.filelist = queue.Queue()
            self.top = '/home/'
            for y in range(12):
                self.u = threading.Thread(target=self.md5hash)
                self.u.daemon = True
                self.u.start()
            for x in range(4):
                self.t = threading.Thread(target=self.threader)
                self.t.daemon = True
                self.t.start()
            main.body(self)
    
        def body(self):
            start = time.time()
            self.text.write("Time now is " + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + "\n")
            for root, dirs, files in os.walk(self.top):
                for f in files:
                    path = os.path.join(root,f)
                    self.filelist.put(path)
            self.t.join()
            self.u.join()
            self.text.write("Total time taken     : " + str(time.time() - start) + "\n")
            print("Log file is created as " + os.getcwd() + "/FileScanLogs.txt")
    
        def md5hash(self):
            while True:
                entry = self.filelist.get()
                //hashing//
                lists = finalhash + ',' + entry
                self.hashlist.put(lists)
                self.filelist.task_done()
    
        def compare(self, hashed, path):
            f = open(os.getcwd() + "/database.csv", 'r')
            for row in f:
                if row.split(':')[1] == hashed:
                    print("Suspicious File!")
                    print("Suspecfs: " + row.split(':')[2] + "File name : " + path)
    
        def threader(self):
            while True:
                item = self.hashlist.get()
                hashes = item.split(',')[0]
                path = item.split(',')[1]
                self.compare(hashes, path)
                self.hashlist.task_done()
    
    main()
    

    def body(self) ,存在线路 self.text.write("Time now is ...") 。此行不会出现在创建的日志文件中。

    问题2:In def compare(self, hashed, path) ,存在一行打印“可疑文件!”和 file path 每次都有哈希冲突。该行始终按顺序打印,因为4个线程 t 正在为谁先打印而斗争。为此,我想我需要知道如何让Python线程运行 print

    问题3:In ,存在行 self.u.join() self.t.join() .命令 join() 据我所知,是一个命令,等待线程终止后再继续。线程均未终止。

    附加信息1:我正在编写多线程,因为我需要稍后将代码转换为多处理。

    附加信息2:如果我在浏览代码时误解了代码中的任何命令/语法,请务必告诉我。

    1 回复  |  直到 9 年前
        1
  •  2
  •   zwer    9 年前

    问题1 :您正在写入文件缓冲区-只有当缓冲区已满、文件句柄已关闭或您显式调用时,它才会刷新到实际文件 flush() self.text.flush() )

    问题2

    如果您只想控制到STDOUT的输出,只要它不干扰线程执行,您可以捕获想要打印的内容,并最终在互斥锁下打印出来(因此一次只有一个线程写入),甚至可以通过管道将其返回到主线程,并让它管理对STDOUT的访问。一个简单的互斥体示例是:

    PRINT_MUTEX = threading.Lock()
    
    def compare(self, hashed, path):  # never mind the inefficiency, we'll get to that later
        out = []  # hold our output buffer
        with open(os.getcwd() + "/database.csv", 'r') as f:
            for row in f:
                row = row.split(':')
                if row[1] == hashed:
                    out.append("Suspicious File!")
                    out.append("Suspecfs: " + row[2] + "File name : " + path)
        if out:
            with self.PRINT_MUTEX:  # use a lock to print out the results
                print("\n".join(out))
    

    compare 结果一次一个,而不是散布结果。如果您想让主线程/进程控制STDOUT,尤其是因为您想将其转换为多处理代码,请选中 this answer .

    :您的线程永远不会退出,因为它们卡在 while True Queue.task_done() 因为它是用来给其他“听众”发信号的(如果他们被 Queue.join()

    你应该使用 threading.Event queue.Queue 只有您可以创建一个特殊属性来表示队列的结束,然后在没有更多要处理的内容时将其放置在队列中,然后让线程在遇到此特殊属性时退出其循环。让我们首先修复代码中的一个大疏忽-您根本没有存储对线程的引用,而是用最后一个线程覆盖它,因此您无法真正控制执行流-与其将最后一个线程引用存储在变量中,不如将所有引用存储在列表中。此外,如果要等待一切结束,请不要使用守护进程线程:

    def __init__(self):
        self.text = open(os.getcwd()+"/FileScanLogs.txt", "a+")  # consider os.path.join()
        self.hashlist = queue.Queue()
        self.filelist = queue.Queue()
        self.hashers = []  # hold the md5hash thread references
        self.comparators = []  # hold the threader thread references
        self.top = '/home/'
        for _ in range(12):  # you might want to consider a ThreadPool instead
            t = threading.Thread(target=self.md5hash)
            t.start()
            self.hashers.append(t)
        for _ in range(4):
            t = threading.Thread(target=self.threader)
            t.start()
            self.comparators.append(t)
        main.body(self)
    

    现在我们可以修改 main.body() 方法,以便将上述特殊值添加到队列的末尾,以便工作线程知道何时停止:

    QUEUE_CLOSE = object()  # a 'special' object to denote end-of-data in our queues
    
    def body(self):
        start = time.time()
        self.text.write("Time:  " + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + "\n")
        for root, dirs, files in os.walk(self.top):
            for f in files:
                path = os.path.join(root, f)
                self.filelist.put(path)
        self.filelist.put(self.QUEUE_CLOSE)  # no more files, signal the end of the filelist
        for t in self.hashers:  # let's first wait for our hashing threads to exit
            t.join()
        # since we're not going to be receiving any new hashes, we can...
        self.hashlist.put(self.QUEUE_CLOSE)  # ... signal the end of the hashlist as well
        for t in self.comparators:  # let's wait for our comparator threads to exit
            t.join()
        self.text.write("Total: " + str(time.time() - start) + "\n")
        self.text.close()  # close the log file (this will also flush the previous content)
        print("Log file is created as " + os.getcwd() + "/FileScanLogs.txt")
    

    因此,我们需要修改工作线程,使其在遇到队列末尾时退出:

    def md5hash(self):
        while self.filelist:
            entry = self.filelist.get()
            if entry is self.QUEUE_CLOSE:  # end of queue encountered
                self.filelist.put(self.QUEUE_CLOSE)  # put it back for the other threads
                break  # break away the processing
            finalhash = whatever_is_your_hash_code(entry)
            lists = finalhash + ',' + entry
            self.hashlist.put(lists)
    
    def threader(self):
        while True:
            item = self.hashlist.get()
            if item is self.QUEUE_CLOSE:  # end of queue encountered
                self.hashlist.put(self.QUEUE_CLOSE)  # put it back for the other threads
                break  # break away the queue
            hashes = item.split(',')[0]
            path = item.split(',')[1]
            self.compare(hashes, path)
    

    main.compare() hash<=>whatever dict 然后在现场进行比较(即。 if hashed in your_map )相反。

    this answer ,但这只是一个主要的PITA,大多数时候不值得经历这些麻烦)。