introduce multithreading to MultiMystery patch creation

I measured a 100 to 200% improvement in total zip creation speed
This commit is contained in:
Fabian Dill 2020-04-10 14:27:54 +02:00
parent b427f03e5f
commit 86d585e2d9
1 changed files with 46 additions and 23 deletions

View File

@ -15,8 +15,11 @@ Configuration can be found in host.yaml
import os
import subprocess
import sys
import threading
import concurrent.futures
def feedback(text:str):
def feedback(text: str):
print(text)
input("Press Enter to ignore and probably crash.")
@ -133,22 +136,29 @@ if __name__ == "__main__":
2: "7z",
3: "bz2"}[zip_format]
ziplock = threading.Lock()
def pack_file(file: str):
with ziplock:
zf.write(os.path.join(output_path, file), file)
print(f"Packed {file} into zipfile {zipname}")
def remove_zipped_file(file: str):
os.remove(os.path.join(output_path, file))
print(f"Removed {file} which is now present in the zipfile")
zipname = os.path.join(output_path, f"ER_{seedname}.{typical_zip_ending}")
print(f"Creating zipfile {zipname}")
ipv4 = (host if host else get_public_ipv4()) + ":" + str(port)
with zipfile.ZipFile(zipname, "w", compression=compression, compresslevel=9) as zf:
for file in os.listdir(output_path):
if file.endswith(".sfc") and seedname in file:
def _handle_file(file: str):
if zip_diffs:
# the main reason for using threading, the patch is created using bsdiff4, which frees the GIL
diff = os.path.split(create_patch_file(os.path.join(output_path, file), ipv4))[1]
pack_file(diff)
if zip_diffs == 2:
@ -157,15 +167,28 @@ if __name__ == "__main__":
pack_file(file)
if zip_roms == 2 and player_name.lower() not in file.lower():
remove_zipped_file(file)
with concurrent.futures.ThreadPoolExecutor() as pool:
futures = []
with zipfile.ZipFile(zipname, "w", compression=compression, compresslevel=9) as zf:
for file in os.listdir(output_path):
if file.endswith(".sfc") and seedname in file:
futures.append(pool.submit(_handle_file, file))
if zip_multidata and os.path.exists(os.path.join(output_path, multidataname)):
pack_file(multidataname)
if zip_multidata == 2:
remove_zipped_file(multidataname)
if zip_spoiler and create_spoiler:
pack_file(spoilername)
if zip_spoiler == 2:
remove_zipped_file(spoilername)
for future in futures:
future.result() # make sure we close the zip AFTER any packing is done
if os.path.exists(os.path.join(output_path, multidataname)):
if os.path.exists("BerserkerMultiServer.exe"):
baseservercommand = "BerserkerMultiServer.exe" # compiled windows