我在Windows环境下,运行Yolov5的代码时,代码中多线程取出数据出现了以下的错误:
RuntimeError:
An attempt has been made to start a new process before the
current process has finished its bootstrapping phase.
This probably means that you are not using fork to start your
child processes and you have forgotten to use the proper idiom
in the main module:
if __name__ == '__main__':
freeze_support()
...
The "freeze_support()" line can be omitted if the program
is not going to be frozen to produce an executable.
Traceback (most recent call last):
File "D:\Software\Anaconda\envs\pytorch\lib\site-packages\torch\utils\data\dataloader.py", line 761, in _try_get_data
data = self._data_queue.get(timeout=timeout)
File "D:\Software\Anaconda\envs\pytorch\lib\multiprocessing\queues.py", line 105, in get
raise Empty
_queue.Empty
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "D:/WorkSpace/Codes/Pycharm/2020/NPyTorch/Minibatchtraing.py", line 24, in <module>
for step, (batch_x, batch_y) in enumerate(loader):
File "D:\Software\Anaconda\envs\pytorch\lib\site-packages\torch\utils\data\dataloader.py", line 345, in __next__
data = self._next_data()
File "D:\Software\Anaconda\envs\pytorch\lib\site-packages\torch\utils\data\dataloader.py", line 841, in _next_data
idx, data = self._get_data()
File "D:\Software\Anaconda\envs\pytorch\lib\site-packages\torch\utils\data\dataloader.py", line 808, in _get_data
success, data = self._try_get_data()
File "D:\Software\Anaconda\envs\pytorch\lib\site-packages\torch\utils\data\dataloader.py", line 774, in _try_get_data
raise RuntimeError('DataLoader worker (pid(s) {}) exited unexpectedly'.format(pids_str))
RuntimeError: DataLoader worker (pid(s) 8528, 8488) exited unexpectedly
可以发现,上面的DataLoader有两个PID 8528, 8488
,表示其有两个进程,而两个进程报错,则说明多进程的设置有问题。
上述错误的提示含义为:您试图在当前进程完成引导阶段之前启动新进程。这可能意味着您没有使用fork来启动子进程,并且忘记了在主模块中使用适当的习语。还有一种情况是,如果您的程序不会被冻结为生成Windows可执行文件,则可以省略 “freeze_support()”
行。
其实真正原因的出现还是Windows操作系统与Linux操作系统的差异。
在Linux操作系统中,其提供了一个fork()系统调用,用于创建子进程,有了fork调用,一个进程在接到新任务时就可以复制出一个子进程来处理新 任务,常见的Apache服务器就是由父进程监听端口,每当有新的http请求时,就fork出子进程来处理新的http请求。
但是,Windows中是并没有fork()系统调用的,是使用的 spawn
命令,那该怎么办呢?
multiprocessing模块本来就是跨平台版本的多进程模块,其设计的时候就考虑到了Linux和Windows操作系统的差异,但因为Windows缺乏linix那种fork, 所以它会有一些额外的限制:
这也就解释了为什么Windows下使用多进程模块 multiprocessing
必须要有主函数存在了,因为 spawn命令需要区分主进程,上述的报错其实就是忽略了第三点的要求。
要解决上面的错误也很简单,在主函数 if __name__ == '__main__':
的第一行加上 multiprocessing.freeze_support()
,使得主进程能够得到区分,这里我是运行Yolov5的代码出错的,我就用其主函数来演示,其修改如下:
import multiprocessing
"""
其他代码
"""
if __name__ == "__main__":
multiprocessing.freeze_support()
opt = parse_opt()
main(opt)