我有一个功能,需要一个包含only图像而没有其他内容的文件夹的路径。但是,我有 3000 多个包含图像的文件夹,还有其他文件(随机 .txt 文件、RTSTRUC 文件等)。
对于每个文件夹,我使用 sh.copy() 将图像移动到 tmp 文件夹中,然后将我的函数指向该文件夹。但我遇到了很长的运行时间。我尝试用 sh.copyfiles() 缩短也发现它很慢。我尝试与多处理库并行化,但遇到了问题,因为每个子进程使用相同的临时文件夹并且存在无意的混合和匹配!
有什么想法吗?
for file in glob.glob(dicom_dir + "/*IMG*"):
shutil.copy(file,tmp_dicom_folder)
提供令人望而却步的运行时间。
有没有办法让我使用临时文件夹进行并行化而不会遇到此问题?为每个进程创建一个临时文件夹听起来很混乱。
使用符号链接而不是副本。为要并行运行的每个进程创建一个临时目录。如果这是 CPU 密集型图像处理,则每个 CPU 略少于一个进程是一个合理的起点,但可能会因各种原因(例如 GPU 使用情况)而改变。
列出您想要处理的文件并将它们的符号链接分散到目录中。在每个符号链接目录上运行程序的副本,每个目录都会获得工作负载的子集。
import itertools
import multiprocessing as mp
import tempfile
from pathlib import Path
import subprocess as subp
dicom_dir = Path("tmp/test")
# assuming each image process takes 1 cpu and you don't want
# to commit all of them... Note: There may be better ways to
# get an accurate count.
cpus = int(mp.cpu_count() * .80) or 1
# build tmp directory for each cpu, populate with symlinks to
# image files and run one process per directory.
with tempfile.TemporaryDirectory() as tmpdir:
root = Path(tmpdir)
cpudirs = [root/f"sym_{x}" for x in range(cpus)]
for cpudir in cpudirs:
cpudir.mkdir()
count = 0
for count, (target, cpudir) in enumerate(
zip(dicom_dir.glob("*IMG*"),
itertools.cycle(cpudirs))):
(cpudir/target.name).symlink_to(target.absolute())
if count < len(cpudirs):
# there were fewer IMG than cpus, remove what we didn't use
del cpudirs[count:]
# TODO: This is a naive way to run the commands and would be slow
# if there is a lot of stdout/err to consume.
processes = [subp.Popen(["the command", cpudir.absolute()])
for cpudir in cpudirs]
for proc in processes:
proc.communicate()