在走这段代码的时候报错了,记录一下我的调试过程,感觉有个思路来走就挺好的。

  • 1、报错与解决

文件名字:ClassifierTest.py

import torch
import torchvision
import torchvision.transforms as transforms
from torchTest import imgShow transform = transforms.Compose([transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
trainset = torchvision.datasets.CIFAR10(root='Resources/CIFAR10', # 存放路径 #!!/Resources/CIFAR10是绝对路径,C:\Resources\CIFAR10
train=True, download=True, # 是否下载训练集
transform=transform) # 图片转换
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True, num_workers=2)
testset = torchvision.datasets.CIFAR10(root='Resources/CIFAR10', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4, shuffle=False, num_workers=2) classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck') dataIter = iter(trainloader)
images, labels = dataIter.next()
imgShow.imshow(torchvision.utils.make_grid(images))
print(' '.join(classes[labels[j]] for j in range(4)))

报错

        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.

关于这个报错,涉及线程问题,改num_workers=0,当然就么事没有,然而,作为一个优秀的程序员,能止步于此吗,不行的。

我百度了一下报错情况,找到这样的解决方案,是可行:

def main():
transform = transforms.Compose([transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
trainset = torchvision.datasets.CIFAR10(root='Resources/CIFAR10', # 存放路径,注:/Resources/CIFAR10是绝对路径,C:\Resources\CIFAR10
train=True, download=True, # 是否下载训练集
transform=transform) # 图片转换
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True, num_workers=2)
testset = torchvision.datasets.CIFAR10(root='Resources/CIFAR10', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4, shuffle=False, num_workers=2)
classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck') dataIter = iter(trainloader)
images, labels = dataIter.next()
imgShow.imshow(torchvision.utils.make_grid(images))
print(' '.join(classes[labels[j]] for j in range(4))) if __name__=='__main__': #不加这句就会报错
main()
  • 2、为什么是main?

整段放在main里面,就安全了——为什么呢?

对于python编程我还是萌新,实在想不明白加个__name__=='__main__'判断有什么魅力。

关于__name__属性:

作为启动脚本,它模块的__name__都是__main__。

此句主要作用在于有时候import,不想运行引用模块中某些语句的时候,以启动模块的名字作为区别。

报错的位置在这里:

C:\Users\13723\AppData\Local\Programs\Python\Python39\Lib\multiprocessing\spawn.py

def _check_not_importing_main():
    if getattr(process.current_process(), '_inheriting', False):
        raise RuntimeError('''
        An attempt has been made to start a new process before the
        current process has finished its bootstrapping phase...''')

getattr(实例, 属性名字, 默认值)

如果有属性,取True,否则取默认值,没有默认值则取False。

_inheriting,查找当前程序的可继承性?没用过,笔者不知道呢。

看不懂(下文有解),只能从方法名字入手,它走这一段为了什么——

检查是不是源自__main__模块,即程序不让由执行脚本import的模块走这一段。

我跑ClassifierTest.py(进程pid1),它在走到

dataIter = iter(trainloader)

里面,由其他模块,再导入了一次ClassifierTest.py(此时是进程pid2)

而当增加判断 __name__==’__main__’,就避免模块陷入执行的死循环。

  • 3、为什么多一个进程?

3.1 现象

为什么会多一个进程,num_workers=2,此句是一个进程两个线程worker,还是两个进程worker呢?

我很奇怪,为什么不是开线程,而是开进程这么个重量级东西。

虽然叫做process,但它应该只干一个事情——毕竟进程的重量级要大于线程。

3.2 线程与进程

这个时候就很纠结线程和进程的区别了,

(参考:https://www.zhihu.com/question/25532384

线程是cpu执行的时间段颗粒,

进程保存上下文,cpu切进进程里面读取上下文(寄存器、指令内容之类)。

这样看来,如果进程是仓库,线程就是仓库里面的机器人,等待CPU来灵魂激活。但是在一个仓库里面工作,必然比在多个仓库里面工作要省事。

所以为什么要开多进程呢?

一个莫名的灵感,让我查了一下fork(),

(参考:https://www.cnblogs.com/liyuan989/p/4279210.html

因为进程、线程是windows系统的概念,unix中只有进程的说法。

在windows当中,进程是资源管理的最小单位,而线程是程序执行的最小单位。

fork创建的一个子进程几乎但不完全与父进程相同。

子进程得到与父进程用户级虚拟地址空间相同的(但是独立的)一份拷贝,

包括文本、数据和bss段、堆以及用户栈等。

子进程还获得与父进程任何打开文件描述符相同的拷贝,

这就意味着子进程可以读写父进程中任何打开的文件,父进程和子进程区别在于它们有着不同的PID。

fork 意为分支,分支与父进程几乎一样的子进程。子进程区别于父进程,两者有不同的pid,但二者的引用均指向相同的地址。

话虽如此,Python里面确实是包含threading,和process模块,那为什么选择process更好?

(参考:https://zhuanlan.zhihu.com/p/20953544)

一个进程,有一个全局锁GIL(Global Interpreter Lock),此设定是为了数据安全。

线程执行时,先获取GIL,执行代码直到sleep或挂起,释放GIL。

所以多线程执行,其实仅是宏观时间上处理多任务,微观时间上仍是顺序处理。

而每个进程有各自独立的GIL,互不干扰,多进程才能在真正意义上实现并行执行(多核CPU同时做多个任务,程序在微观时间上同时执行)。

3.3 Python中,worker是进程

为什么会再读一次ClassifierTest.py,从堆栈看,是这里:

(注,以下截图可能取自不同次调试,所以父pid会不同)

走了 exec(code, run_globals) 导致再此导入 ClassifierTest.py 。

再往前走frame not available,也即IDE只能看到spawn_main函数。

(spawn应该就是孵化了,孵化进程的,还挺有蛇下蛋的感觉)

更之前的调用情况没有了,可以猜是不是新进程直接调用spawn_main了,那就找spawn_main引用。

(可能pyCharm我还没get灵魂用法,spawn_main引用我是用notepad++查找全局的)

Python39\Lib\multiprocessing\popen_spawn_win32.py

前后呼应:

在查看堆栈的过程中,恰巧看到了_inheriting的赋值:

堆栈可以看到对_inheriting赋值,此时就很明了表示是否子进程,此处赋值True。

再者,inheriting是ing结尾,表示进行时状态;如果是表示继承性,应该叫inherited,如此看来这个编程就很细心,自己写程序的时候也得注意。

 3.4 num_workers=2 的结果

前文设置num_workers = 2,此时就是父进程带着两个子进程,

__name__==’__main__’ 的处理,阻止了子进程由于调用 ClassifierTest.py 而再生子子进程的子孙无穷尽也。

主线程12012 它有两个worker,分别是 15480 和 7036 。

(这个数值是系统分配的pid编号,区分进程的代号,每次启动程序都不同)

15480 和 7036 带着自己的Queue,dataloader.py完成了这个配置。

dataIter = iter(trainloader)
images, labels = dataIter.next()

当执行 next(),程序会读取象 dataIter 当中的 _data_queue ,这个数据由两个子进程各自传入。

data = self._data_queue.get(timeout=timeout)

具体实现看这个类:

C:\Users\13723\PycharmProjects\pythonProject\venv\Lib\site-packages\torch\utils\data\dataloader.py

class _MultiProcessingDataLoaderIter(_BaseDataLoaderIter):
pass
  • 4、结语

  由一个小小的报错,能“查漏补缺”知识漏洞就挺好的,锻炼思维也挺好的。共勉。

python进程 - 调试报错 you are not using fork to start your child processes的更多相关文章

  1. 【python】python读取文件报错UnicodeDecodeError: 'gbk' codec can't decode byte 0xac in position 2: illegal multibyte sequence

    python读取文件报错UnicodeDecodeError: 'gbk' codec can't decode byte 0xac in position 2: illegal multibyte ...

  2. 【python】python安装tensorflow报错:python No matching distribution found for tensorflow==1.12.0

    python安装tensorflow报错:python No matching distribution found for tensorflow==1.12.0 python版本是3.7.2 要安装 ...

  3. 真机调试报错error ==Error Domain=NSURLErrorDomain Code=-1009 "似乎已断开与互联网的连接。"

    真机调试报错error ==Error Domain=NSURLErrorDomain Code=-1009 "似乎已断开与互联网的连接." 请注意,错误代码是-1009,网上关于 ...

  4. 今天微信小程序发现wx.request不好使了,调试报错: 小程序要求的 TLS 版本必须大于等于 1.2

    今天微信小程序发现wx.request不好使了,调试报错: 小程序要求的 TLS 版本必须大于等于 1.2 查官方文档 解决方法 在 PowerShell中运行以下内容, 然后重启服务器 # Enab ...

  5. mac下python环境pip报错[SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:590) 的解决方法

    1.mac下python环境pip报错: issuserdeMacBook-Pro:~ issuser$ pip install pyinstallerCollecting pyinstaller  ...

  6. Django中修改DATABASES后,执行python manage.py ****报错!UnicodeEncodeError

    Django中修改DATABASES后,执行python manage.py ****报错!UnicodeEncodeError: 'latin-1' codec can't encode chara ...

  7. python 安装模块报错 response.py", line 302, in _error_catcher

    python 安装模块报错 Exception:Traceback (most recent call last): File "/usr/share/python-wheels/urlli ...

  8. CLR调试报错“Visual Studio远程调试监视器 (MSVSMON.EXE) 的 64 位版本无法调试 32 位进程或 32 位转储。请改用 32 位版本”的解决

    Win7 64位电脑上进行visual studio的数据库项目的CLR存储过程进行调试时,报错: ---------------------------Microsoft Visual Studio ...

  9. VS2017 启动调试报错:ID为{....}进程未启动解决方案

    今天遇到这么一个问题,打开VS启动调试,始终报错,如下图: 我重启VS,甚至重启电脑都不得行,那个进程号还在变化,就在网上查找资料,各式各样的解决方案,这里我记录我成功的方案. 打开项目文件地址,在解 ...

  10. 【.NET调用Python脚本】C#调用python requests类库报错 'module' object has no attribute '_getframe' - IronPython 2.7

    最近在开发微信公众号,有一个自定义消息回复的需求 比如用户:麻烦帮我查询一下北京的天气? 系统回复:北京天气,晴,-℃... 这时候需要根据关键字[北京][天气],分词匹配需要执行的操作,然后去调用天 ...

随机推荐

  1. 体验.NET与文件存储服务MinIO

    对象文件存储服务(OSS)主要用于存储零散的文件,和直接存储到本地文件系统中相比,有以下的几个优势: 跨服务器可用 兼容Amazon S3 API 横向扩容 高可用 支持加密 MinIO就是一个高性能 ...

  2. 【网站搭建】开源社区Flarum搭建记录

    环境 服务器系统:腾讯云 OpenCloudOS 宝塔版本:免费版8.0.1 Nginx:1.24.0 MySQL:5.7.42 PHP:8.1.21 萌狼蓝天 2023年8月7日 PHP设置 1.安 ...

  3. Anaconda下载安装及Spyder使用Python

    第一:选择编程语言, C++ Java Python等,量化交易广泛使用Python开发策略. 第二:选择软件,Anaconda 或者 PyCharm,龙哥选用Anaconda,因为 Anaconda ...

  4. Gitlab 实现仓库完全迁移

    方法一:最快 gitlab用url导入注意事项看图 方法二 首先需要在新的服务服务器上新建一个项目 然后用 Git Bash 执行以下命令 git clone --mirror 项目原代码仓库地址 / ...

  5. Qt编写安防视频监控系统23-图片地图

    一.前言 图片地图这个模块是后面新增加进去的,主要是安防领域还有很多应用场景是一个区域比如就一个学校,提供一个学校的平面图或者鸟瞰图,然后在该地图上放置对应的摄像机,双击该摄像机图标可以查看对应的实时 ...

  6. Qt编写地图综合应用9-行政区划

    一.前言 行政区划在地图应用中非常有用,行政区划是行政区域划分的简称,是国家为了进行分级管理而实行的区域划分,百度地图提供的内置的函数类支持传入行政区划的名称来获取对应的边界点集合,然后根据该集合来绘 ...

  7. 如何在众多Ubuntu版本中挑选出最适配自身需求的系统版本?用德承工控机GM-1100来深度剖析其中的门道

    Ubuntu是一款基于Debian GNU/Linux,支持x86.amd64(x64)和ppc架构,以桌面应用为主的Linux操作系统.其名称来自非洲南部的语言"ubuntu"( ...

  8. 开源商业化 Sealos 如何做到月入 160万

    去年我写了一篇也是讲开源商业化的文章,当时是月入 30 万,一年过去了,我们整整涨了 5 倍多.本文理论结合实践,比较干货,希望对大家有帮助. 我们的现状,谁在给我们付钱 第一,开发者,我们已经近 2 ...

  9. C Primer Plus 第6版 第八章 编程练习参考答案

    编译环境VS Code+WSL GCC 源码请到文末下载 . 我给第一题写了Linux shell脚本,感兴趣的同学可以尝试修改并运行一下. /*第1题************************ ...

  10. CDS标准视图:维护包描述 I_MaintPackageTextData

    视图名称:维护包描述 I_MaintPackageTextData 视图类型:基础 视图代码: 点击查看代码 @EndUserText.label: 'Maintenance Package - Te ...