用于多处理的 tkinter 进度条
tkinter progressbar for multiprocessing
我有一个加密文件的程序,我使用多处理来使其更快,但我在使用 tkinter 进度条时遇到问题。
我已经实现了它,但它立即完成或滞后于两者之间。
进度条刚刚完成到 100%,但文件仍在加密,我没有收到任何错误。
files 包含文件列表。
完整代码在这里 - https://codeshare.io/pq8YxE
下面是我实现它的方式。
def progbar():
global pb_lable
global percent
global pbar
global percentlabel
global pbar_frame
pb_lable = tk.Label(root, text='Progress', font = "Raleway 13 bold")
pb_lable.grid(row=5, columnspan=2, sticky='w', padx=(35))
pbar_frame = tk.Frame(root)
pbar_frame.grid(row=6, columnspan=2)
pbar = Progressbar(pbar_frame,orient='horizontal',length=500,mode='determinate')
pbar.grid(row=7,column=0, pady=10, padx=20)
percent = tk.StringVar()
percentlabel = tk.Label(root, textvariable=percent, font='Raleway 15')
percentlabel.grid(row=5,columnspan=2,pady=10, padx=120, sticky='w')
def encryptfn(key, a):
f = Fernet(key)
return f.encrypt(a)
def enc(key, process_pool, file):
task = len(files)
x = 0
with open(file,'rb') as original_file:
original = original_file.read()
encrypted = process_pool.apply(encryptfn, args=(key, original,))
with open (file,'wb') as encrypted_file:
encrypted_file.write(encrypted)
pbar['value']+=100/task
x = x+1
percent.set(str(int((x/task)*100))+'%')
root.update_idletasks()
def encfile():
password = bytes('asdasd', 'utf-8')
salt = bytes('zxcasd','utf-8')
global files
files = filistbox.get(0,'end')
if len(files) == 0:
fierrorbox()
elif len(password) == 0:
passerrorbox()
else:
file_enc_button['state']='disabled'
browsefi['state']='disabled'
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=100,
backend=default_backend())
key = base64.urlsafe_b64encode(kdf.derive(password))
MAX_THREADS = 300
pool_size = min(MAX_THREADS, cpu_count(), len(files))
process_pool = Pool(pool_size)
thread_pool = ThreadPool(min(MAX_THREADS, len(files)))
worker = partial(enc, key, process_pool)
thread_pool.map(worker, files)
root.event_generate("<<encryption_done>>")
file_enc_button['state']='active'
browsefi['state']='active'
def run_encfile():
root.bind('<<encryption_done>>', encryption_done)
Thread(target=encfile).start()
def encryption_done(*args):
fiencdone()
if __name__ == '__main__':
root = tk.Tk()
browsefi = tk.Button(root, text='Browse', command=fibrowse, borderwidth=3)
browsefi.grid(row=2,column=0,padx=5, pady=5)
## File list ##
filist_frame = tk.Frame(root)
filist_frame.grid(row=3, columnspan=2)
filistbox = tk.Listbox(filist_frame, width=40, height=10)
filistbox.grid(row=3,columnspan=2, pady=10)
## Button ##
fibutton_frame = tk.Frame(root)
fibutton_frame.grid(row=4, columnspan=2)
file_enc_button = tk.Button(fibutton_frame, text='Encrypt', width=15, command=run_encfile, borderwidth=3)
file_enc_button.grid(row=4,column=0,padx=10,pady=15)
progbar()
percent.set('0%')
root.mainloop()
问题出现在函数 enc
中,您不断将变量 x
重置回 0。
您需要一个初始化为 0 的全局变量,例如 tasks_completed
,它跟踪已完成的加密次数,并在 enc
内使用语句 [=16] 递增=].从技术上讲,这等同于 tasks_completed = tasks_completed + 1
并且不是原子操作,理论上线程可能会在读取 tasks_completed
的值后被中断,因此两个线程将更新 tasks_completed
到相同的值。因此,为了完全安全,此更新应该在 multithreading.Lock
的控制下完成,以确保一次只有一个线程可以进行更新。
将函数 enc
替换为:
from threading import Lock
tasks_completed = 0
def enc(key, process_pool, lock, file):
global tasks_completed
with open(file,'rb') as original_file:
original = original_file.read()
encrypted = process_pool.apply(encryptfn, args=(key, original,))
with open (file,'wb') as encrypted_file:
encrypted_file.write(encrypted)
encrypted = process_pool.apply(encryptfn, args=(key, file,))
with lock:
tasks_completed += 1
percentage_completed = int((tasks_completed / len(files)) * 100)
pbar['value'] = percentage_completed
percent.set(f'{percentage_completed}%')
root.update_idletasks()
并创建一个multiprocessing.Lock
实例并将其传递给函数encfile
中的enc
,修改函数如下:
lock = Lock() # create lock
# add additional lock argument to enc:
worker = partial(enc, key, process_pool, lock)
我有一个加密文件的程序,我使用多处理来使其更快,但我在使用 tkinter 进度条时遇到问题。
我已经实现了它,但它立即完成或滞后于两者之间。 进度条刚刚完成到 100%,但文件仍在加密,我没有收到任何错误。
files 包含文件列表。
完整代码在这里 - https://codeshare.io/pq8YxE
下面是我实现它的方式。
def progbar():
global pb_lable
global percent
global pbar
global percentlabel
global pbar_frame
pb_lable = tk.Label(root, text='Progress', font = "Raleway 13 bold")
pb_lable.grid(row=5, columnspan=2, sticky='w', padx=(35))
pbar_frame = tk.Frame(root)
pbar_frame.grid(row=6, columnspan=2)
pbar = Progressbar(pbar_frame,orient='horizontal',length=500,mode='determinate')
pbar.grid(row=7,column=0, pady=10, padx=20)
percent = tk.StringVar()
percentlabel = tk.Label(root, textvariable=percent, font='Raleway 15')
percentlabel.grid(row=5,columnspan=2,pady=10, padx=120, sticky='w')
def encryptfn(key, a):
f = Fernet(key)
return f.encrypt(a)
def enc(key, process_pool, file):
task = len(files)
x = 0
with open(file,'rb') as original_file:
original = original_file.read()
encrypted = process_pool.apply(encryptfn, args=(key, original,))
with open (file,'wb') as encrypted_file:
encrypted_file.write(encrypted)
pbar['value']+=100/task
x = x+1
percent.set(str(int((x/task)*100))+'%')
root.update_idletasks()
def encfile():
password = bytes('asdasd', 'utf-8')
salt = bytes('zxcasd','utf-8')
global files
files = filistbox.get(0,'end')
if len(files) == 0:
fierrorbox()
elif len(password) == 0:
passerrorbox()
else:
file_enc_button['state']='disabled'
browsefi['state']='disabled'
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=100,
backend=default_backend())
key = base64.urlsafe_b64encode(kdf.derive(password))
MAX_THREADS = 300
pool_size = min(MAX_THREADS, cpu_count(), len(files))
process_pool = Pool(pool_size)
thread_pool = ThreadPool(min(MAX_THREADS, len(files)))
worker = partial(enc, key, process_pool)
thread_pool.map(worker, files)
root.event_generate("<<encryption_done>>")
file_enc_button['state']='active'
browsefi['state']='active'
def run_encfile():
root.bind('<<encryption_done>>', encryption_done)
Thread(target=encfile).start()
def encryption_done(*args):
fiencdone()
if __name__ == '__main__':
root = tk.Tk()
browsefi = tk.Button(root, text='Browse', command=fibrowse, borderwidth=3)
browsefi.grid(row=2,column=0,padx=5, pady=5)
## File list ##
filist_frame = tk.Frame(root)
filist_frame.grid(row=3, columnspan=2)
filistbox = tk.Listbox(filist_frame, width=40, height=10)
filistbox.grid(row=3,columnspan=2, pady=10)
## Button ##
fibutton_frame = tk.Frame(root)
fibutton_frame.grid(row=4, columnspan=2)
file_enc_button = tk.Button(fibutton_frame, text='Encrypt', width=15, command=run_encfile, borderwidth=3)
file_enc_button.grid(row=4,column=0,padx=10,pady=15)
progbar()
percent.set('0%')
root.mainloop()
问题出现在函数 enc
中,您不断将变量 x
重置回 0。
您需要一个初始化为 0 的全局变量,例如 tasks_completed
,它跟踪已完成的加密次数,并在 enc
内使用语句 [=16] 递增=].从技术上讲,这等同于 tasks_completed = tasks_completed + 1
并且不是原子操作,理论上线程可能会在读取 tasks_completed
的值后被中断,因此两个线程将更新 tasks_completed
到相同的值。因此,为了完全安全,此更新应该在 multithreading.Lock
的控制下完成,以确保一次只有一个线程可以进行更新。
将函数 enc
替换为:
from threading import Lock
tasks_completed = 0
def enc(key, process_pool, lock, file):
global tasks_completed
with open(file,'rb') as original_file:
original = original_file.read()
encrypted = process_pool.apply(encryptfn, args=(key, original,))
with open (file,'wb') as encrypted_file:
encrypted_file.write(encrypted)
encrypted = process_pool.apply(encryptfn, args=(key, file,))
with lock:
tasks_completed += 1
percentage_completed = int((tasks_completed / len(files)) * 100)
pbar['value'] = percentage_completed
percent.set(f'{percentage_completed}%')
root.update_idletasks()
并创建一个multiprocessing.Lock
实例并将其传递给函数encfile
中的enc
,修改函数如下:
lock = Lock() # create lock
# add additional lock argument to enc:
worker = partial(enc, key, process_pool, lock)