data = self._data_queue.get(timeout=timeout)RuntimeError: DataLoader worker (pid(s) 8528, 8488) exit

报错输出

我在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, 所以它会有一些额外的限制:

  • 不管是绑定还是未绑定的方法, 都不要直接作为参数传给Process初始化的target, 相反应该要用普通的函数代替
  • 子进程在访问全局变量时, 可能会与父进程的值不同 ( 模块级别的常量没这问题 )
  • 开启新Python解析器或者创建新process时, 确定主模块能够安全的导入.

这也就解释了为什么Windows下使用多进程模块 multiprocessing 必须要有主函数存在了,因为 spawn命令需要区分主进程,上述的报错其实就是忽略了第三点的要求。

解决方法

要解决上面的错误也很简单,在主函数 if __name__ == '__main__': 的第一行加上 multiprocessing.freeze_support() ,使得主进程能够得到区分,这里我是运行Yolov5的代码出错的,我就用其主函数来演示,其修改如下:

import multiprocessing


"""
其他代码
"""

if __name__ == "__main__":
    multiprocessing.freeze_support()
    opt = parse_opt()
    main(opt)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在这段代码中,有几个问题可以被改进。首先,类 `Processor` 中的全局变量 `aco` 可能会导致并发问题,在多进程环境下应该避免使用全局变量。其次,代码中出现了 `time.sleep()`,这会阻塞当前进程并造成性能瓶颈,应该尽量避免使用。 以下是可能的改进方案: 1. 将 `aco` 变量改为实例变量,避免多进程之间的并发问题。 2. 使用 `Queue` 或其他进程间通信机制替代全局变量,避免多进程之间的竞争。 3. 将 `time.sleep()` 改为使用定时器或者事件,避免阻塞进程并提高程序的性能。 4. 在多进程环境中,使用 `if __name__ == '__main__':` 来避免创建子进程时出现递归调用的问题。 以下是修改后的代码示例: ```python import multiprocessing from queue import Queue import time class Processor(): def __init__(self): self._inspect_step = int(cfg.get('PROCESS', 'INSPECT_STEP')) self._aco = 0 self._queue = Queue() def capture_img(self): self._aco += 1 self._cam.stream_on() raw_image = self._cam.data_stream[0].get_image() if raw_image is None: print("Getting image failed.\n") return None print("Frame ID: {} Height: {} Width: {} Count: {}\n".format(raw_image.get_frame_id(), raw_image.get_height(), raw_image.get_width(), self._aco - 2)) numpy_image = raw_image.get_numpy_array() if numpy_image is None: return None img = Image.fromarray(numpy_image, 'L') if self._issave: picfile = '{}/{}.bmp'.format(self._picpath, self._piccount) self._piccount = self._piccount + 1 img.save(picfile) if self._isshow: w, h = img.size scale = min(1.0 * IMG_RESIZE_W / w, 1.0 * IMG_RESIZE_H / h) self._img = ImageTk.PhotoImage(image=img.resize((int(w * scale), int(h * scale)), Image.ANTIALIAS)) self._show_cb(self._img) self._cam.stream_off() return img def process_img(self, img): return PROC_OK def inspect(self): print("process2") while self._running: time.sleep(1) self._queue.put("task") def rotate(self): count = 0 while self._running: v = self._dgl.qpin(ROT) if len(v) > 0: count = count + sum(v) if count > self._inspect_step: self._aco += 1 img = self.capture_img() count = count - self._inspect_step try: task = self._queue.get(block=False) if task == "task": print("processing task") except: pass if __name__ == '__main__': p = Processor() p._running = True task2 = multiprocessing.Process(target=p.inspect) task2.start() task1 = multiprocessing.Process(target=p.rotate) task1.start() ``` 请注意,这里只是对原始代码的一些修改建议,并不能保证这样的修改能够完全解决问题。在实际环境中,还需要根据具体情况进行调整和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值