本文主要是介绍Python多线程文件去重,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
注:本文基于python2.7.5
之前已经使用python写过文件去重的脚本(Windows下使用python删除重复图片),但是文件多了脚本运行比较慢,因此改进一下,使用多线程感受一下效果。
思路还是不变,通过比较文件的MD5值确定是否是同一文件,相似图片暂不考虑,有机会研究一下。
代码如下:
#-*- coding: UTF-8 -*-import threading
import os
import sys
import hashlib
import time
import shutildef thread_run(name):threadLockForPrint.acquire()print("starting: Thread" + str(name)) #如果不使用锁,打印可能出现串行的情况,串口也是全局资源threadLockForPrint.release()threadLockForPhoto.acquire()while len(photoes) > 0:photo = photoes.pop()threadLockForPhoto.release()photomd5 = getmd5(photo)threadLockForMD5.acquire()if photomd5 not in photoMd5List:photoMd5List.append(photomd5)threadLockForMD5.release()else:threadLockForMD5.release()threadLockForIdentical.acquire()identicalPhotoes.append(photo)threadLockForIdentical.release()threadLockForPhoto.acquire()threadLockForPhoto.release()def getmd5(file):if not os.path.isfile(file): return f = open(file,'rb')md5 = hashlib.md5()md5.update(f.read())f.close()return md5.hexdigest() def getFiles(targetDir):allfiles = []for path,dir,filelist in os.walk(targetDir):for filename in filelist:allfiles.append(os.path.join(path, filename))return allfilesif __name__ == "__main__":dirname = sys.argv[1]if len(sys.argv) == 3:identicalDir = sys.argv[2]else:identicalDir = ""threadLockForPhoto = threading.Lock()threadLockForMD5 = threading.Lock()threadLockForIdentical = threading.Lock()threadLockForPrint = threading.Lock()global identicalPhotoesidenticalPhotoes = []global photoMd5ListphotoMd5List = []global photoesphotoes = getFiles(dirname)threads = []start = time.time()for i in range(5): #create 5 threadst = threading.Thread(target=thread_run, args=(i+1,))t.start()threads.append(t)for thread in threads:thread.join()end = time.time()last = end - startprint("There are " + str(len(identicalPhotoes)) + " identical photo(es)")if os.path.exists(identicalDir):for i in identicalPhotoes:shutil.move(i, identicalDir)print(i.decode('gbk'))print("main thread exit: lasts for " + str(last) + "s")
脚本接收两个入参,一个是需要去重的文件目录(必须),另一个是存放重复文件的目录(可选)。如果没有指定存放重复文件的目录,则不移动重复文件,仅打印重复文件数量。
主要是使用threading这个模块实现,通过继承threading.Thread,并重写__init__和run函数,就能将自己需要运行的操作定义在线程中了。这里我们定义两个线程,然后调用线程的start()函数,之后就会调用我们定义的run函数,执行我们希望的操作。为防止主线程在子线程前结束,调用join()函数,等待所有子线程结束后,主线程再退出。
因为有多个线程在运行,我们不得不考虑同步的问题,不然数据就会出现不一致了。考虑到我们有三个全局变量,所有照片的列表,非重复照片的MD5值列表,以及重复图片列表,因此我们定义三个线程锁,当然也可以只定义一个锁,但是锁的粒度过大的话就很影响线程的执行效率,因此我们细化锁的粒度,这样线程间对全局资源的操作更为灵活。
加锁的操作在对列表读取、添加前,操作完成后,立马释放该锁,以便其他线程可以持有该锁。
这篇关于Python多线程文件去重的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!