Python 为for循环创建主进程
这个程序返回视频的分辨率,但由于我需要一个大规模的项目,我需要多处理。我曾经尝试过使用不同的函数进行并行处理,但那只会多次运行它,而不会使其有效。我正在发布整个代码。你能帮我创建一个包含所有内核的主进程吗Python 为for循环创建主进程,python,python-3.x,process,python-multiprocessing,moviepy,Python,Python 3.x,Process,Python Multiprocessing,Moviepy,这个程序返回视频的分辨率,但由于我需要一个大规模的项目,我需要多处理。我曾经尝试过使用不同的函数进行并行处理,但那只会多次运行它,而不会使其有效。我正在发布整个代码。你能帮我创建一个包含所有内核的主进程吗 导入操作系统 从tkinter.filedialog导入askdirectory 从moviepy.editor导入视频文件剪辑 如果名称=“\uuuuu main\uuuuuuuu”: dire=askdirectory() d=可怕的[:] 印刷品(可怕) 死亡=os.listdir(可怕
导入操作系统
从tkinter.filedialog导入askdirectory
从moviepy.editor导入视频文件剪辑
如果名称=“\uuuuu main\uuuuuuuu”:
dire=askdirectory()
d=可怕的[:]
印刷品(可怕)
死亡=os.listdir(可怕)
印刷品(死亡)
对于死亡中的i:#多处理此循环
可怕的=d
dire+=f“/{i}”
v=视频文件剪辑(dire)
打印(f“{i}:{v.size}”)
这段代码运行良好,但我需要帮助为for循环单独创建一个主进程(使用所有内核)。你能原谅我对多重处理感到愤怒的变量名吗。另外,如果您有提高代码效率的技巧,我将不胜感激。我想您是,假设目录中的每个文件都是视频剪辑。我假设处理视频剪辑是一个I/O绑定的“进程”,线程是合适的。在这里,我随意地将20个线程的线程池包装成这样:
MAX_WORKERS = 20 # never more than this
N_WORKERS = min(MAX_WORKERS, len(death))
在性能下降之前,您必须测试MAX_WORKERS的大小。这可能是一个较低的数字,不是因为您的系统无法支持大量线程,而是因为并发访问磁盘上可能分布在介质上的多个文件可能效率低下
import os
from tkinter.filedialog import askdirectory
from moviepy.editor import VideoFileClip
from concurrent.futures import ThreadPoolExecutor as Executor
from functools import partial
def process_video(parent_dir, file):
v = VideoFileClip(f"{parent_dir}/{file}")
print(f"{file}: {v.size}")
if __name__ == "__main__":
dire = askdirectory()
print(dire)
death = os.listdir(dire)
print(death)
worker = partial(process_video, dire)
MAX_WORKERS = 20 # never more than this
N_WORKERS = min(MAX_WORKERS, len(death))
with Executor(max_workers=N_WORKERS) as executor:
results = executor.map(worker, death) # results is a list: [None, None, ...]
更新
根据@Reishin的说法,
moviepy
导致执行ffmpeg
可执行文件,从而最终创建一个完成工作的流程。因此,我们在这里也没有必要使用多处理。我想,假设目录中的每个文件都是视频剪辑。我假设处理视频剪辑是一个I/O绑定的“进程”,线程是合适的。在这里,我随意地将20个线程的线程池包装成这样:
MAX_WORKERS = 20 # never more than this
N_WORKERS = min(MAX_WORKERS, len(death))
在性能下降之前,您必须测试MAX_WORKERS的大小。这可能是一个较低的数字,不是因为您的系统无法支持大量线程,而是因为并发访问磁盘上可能分布在介质上的多个文件可能效率低下
import os
from tkinter.filedialog import askdirectory
from moviepy.editor import VideoFileClip
from concurrent.futures import ThreadPoolExecutor as Executor
from functools import partial
def process_video(parent_dir, file):
v = VideoFileClip(f"{parent_dir}/{file}")
print(f"{file}: {v.size}")
if __name__ == "__main__":
dire = askdirectory()
print(dire)
death = os.listdir(dire)
print(death)
worker = partial(process_video, dire)
MAX_WORKERS = 20 # never more than this
N_WORKERS = min(MAX_WORKERS, len(death))
with Executor(max_workers=N_WORKERS) as executor:
results = executor.map(worker, death) # results is a list: [None, None, ...]
更新
根据@Reishin的说法,
moviepy
导致执行ffmpeg
可执行文件,从而最终创建一个完成工作的流程。因此,我们在这里也没有必要使用多处理。moviepy
只是ffmpeg
的包装器,设计用于编辑剪辑,因此一次只能处理一个文件-性能相当差。每次调用多个文件的新进程都很耗时。最后,选择错误的库可能导致需要多个进程
我建议改为使用,它为ffmpeg提供了直接的py绑定,并具有良好的性能:
import av
import os
from tkinter.filedialog import askdirectory
import multiprocessing
from concurrent.futures import ThreadPoolExecutor as Executor
MAX_WORKERS = int(multiprocessing.cpu_count() * 1.5)
def get_video_resolution(path):
container = None
try:
container = av.open(path)
frame = next(container.decode(video=0))
return path, f"{frame.width}x{frame.height}"
finally:
if container:
container.close()
def files_to_proccess():
video_dir = askdirectory()
return (full_file_path for f in os.listdir(video_dir) if (full_file_path := os.path.join(video_dir, f)) and not os.path.isdir(full_file_path))
def main():
for f in files_to_proccess():
print(f"{os.path.basename(f)}: {get_video_resolution(f)[1]}")
def main_multi_threaded():
with Executor(max_workers=MAX_WORKERS) as executor:
for path, resolution in executor.map(get_video_resolution, files_to_proccess()):
print(f"{os.path.basename(path)}: {resolution}")
if __name__ == "__main__":
#main()
main_multi_threaded()
以上是单线程和多线程实现,具有最佳并行设置(如果绝对需要多线程)
moviepy
只是ffmpeg
的包装器,用于编辑剪辑,因此一次只能处理一个文件,性能相当差。每次调用多个文件的新进程都很耗时。最后,选择错误的库可能导致需要多个进程
我建议改为使用,它为ffmpeg提供了直接的py绑定,并具有良好的性能:
import av
import os
from tkinter.filedialog import askdirectory
import multiprocessing
from concurrent.futures import ThreadPoolExecutor as Executor
MAX_WORKERS = int(multiprocessing.cpu_count() * 1.5)
def get_video_resolution(path):
container = None
try:
container = av.open(path)
frame = next(container.decode(video=0))
return path, f"{frame.width}x{frame.height}"
finally:
if container:
container.close()
def files_to_proccess():
video_dir = askdirectory()
return (full_file_path for f in os.listdir(video_dir) if (full_file_path := os.path.join(video_dir, f)) and not os.path.isdir(full_file_path))
def main():
for f in files_to_proccess():
print(f"{os.path.basename(f)}: {get_video_resolution(f)[1]}")
def main_multi_threaded():
with Executor(max_workers=MAX_WORKERS) as executor:
for path, resolution in executor.map(get_video_resolution, files_to_proccess()):
print(f"{os.path.basename(path)}: {resolution}")
if __name__ == "__main__":
#main()
main_multi_threaded()
以上是单线程和多线程实现,具有最佳并行设置(如果绝对需要多线程)您必须在
中使用线程或多处理,以便在独立进程中运行每个VideoFileClip
,不要对
使用。你必须在for
-循环中使用线程或多处理,以在单独的进程中运行每个视频文件剪辑
,而不要对
使用。在这种情况下,moviepy
库只是ffmpeg可执行文件的包装器。如果最终会产生一个新的进程,为什么还要创建这么多无用的线程/进程呢?对于打开的子线程,最好使用一个线程和观察程序-processes@Reishin嗯,你似乎比我更了解电影。我建议您编写自己的答案,以准确地解释生成多个子流程的策略。谈话很棒,代码更好。无需掌握库,只需快速搜索并查看GitHub上的代码即可。库的主要用途是编辑剪辑,而不是快速处理一堆元信息。结论是,在这种情况下,使用错误的libno need,moviepy
lib只是ffmpeg可执行文件的包装。如果最终会产生一个新的进程,为什么还要创建这么多无用的线程/进程呢?对于打开的子线程,最好使用一个线程和观察程序-processes@Reishin嗯,你似乎比我更了解电影。我建议您编写自己的答案,以准确地解释生成多个子流程的策略。谈话很棒,代码更好。无需掌握库,只需快速搜索并查看GitHub上的代码即可。库的主要用途是编辑剪辑,而不是快速处理一堆元信息。结论是-使用错误的libI无法使用第二种解决方案,因为av库由于某些错误而无法加载。您有任何错误吗advice@ViditAggarwal支持python版本的av库以whl
文件的形式提供,可随时使用。请确保您使用Python 3.5、3.6、3.7或3.8,或者直接从PyPi下载文件:我不能使用第二种解决方案,因为av库不会加载du