250408_解决加载大量数据集速度过慢,耗时过长的问题

250408_解决加载Cifar10等大量数据集速度过慢,耗时过长的问题(加载数据时多线程的坑)

在做Cifar10图像分类任务时,发现每个step时间过长,且在资源管理器中查看显卡资源调用异常,主要表现为,显卡周期性调用,呈现隔一会儿动一下的情况(间隔时间过大导致不能同时截到两个峰值)。

image-20250408224446220

通过检测每步耗费时间发现,载入数据集的时间远远大于前向处理的时间。

在以下参数情况下

batch_size=16
num_workers=20 # 线程数

载入Cifai10数据集的时间为60s左右,前向计算时间仅为0.002s,浪费了大量的时间用于载入及传输数据。

image-20250408230936264

image-20250408225808623

先说结论,是多线程的问题,线程过多导致多线程冲突,修改num_workers=0即可解决问题

解决过程

修改过程中查阅很多资料和大佬博客,尝试了重新定义自己的dataset方法,将transform定义到初始化方法中,避免每获取一次数据就执行一遍transform,而是改为在把数据载入内存时一次全部处理完(详见解决pytorch中Dataloader读取数据太慢的问题_dataloader数据读取慢-CSDN博客

然后重新定义自己加载数据的方法,大佬文中没给加载的方法,我这里补充

def data_loader(batch_size=4,num_workers=2):
    """
    :param batch_size: 批次大小
    :param num_workers: 线程数
    :return:train_loader:训练数据加载器
            test_loader:测试数据加载器
            class:分类类别
    """
    root_dir="./data"
    transform=transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5)),
    ])

    train_dataset = CUDACIFAR10(
        root=root_dir,
        train=True,
        to_cuda=True,  # 使用XPU(或GPU)
        half=False,  # 不使用半精度浮点数
        download=True,  # 如果数据集尚未下载,则下载
        pre_transform=transform
    )

    trainloader = DataLoader(
        dataset=train_dataset,
        batch_size=batch_size,
        shuffle=True,
        num_workers=num_workers
    )

    test_dataset = CUDACIFAR10(
        root=root_dir,
        train=False,
        to_cuda=True,  # 使用XPU(或GPU)
        half=False,  # 不使用半精度浮点数
        download=True,  # 如果数据集尚未下载,则下载
        pre_transform=transform
    )

    testloader = DataLoader(
        dataset=test_dataset,
        batch_size=batch_size,
        shuffle=True,
        num_workers=num_workers
    )
    
    classes=('plane','car','bird','cat','deer','dog','frog','horse','ship','truck')
    return trainloader,testloader,classes

然后加载数据集发现报错:

RuntimeError: _share_filename_: only available on CPU

多线程加载仅支持在cpu上进行,我们这样的处理方法已经提前将数据载入到gpu或xpu上,无法使用多线程,遂将num_workers修改为0,发现问题解决了。数据载入速度变得很快。遂准备复现并记录问题,发现把大佬数据类代码注释后,使用官方cifar10数据类代码,加载速度仍较快,核实发现应该是多线程的问题。

尝试多组参数

batch_size=16
num_workers=0

每个step执行时间为11-12s左右

image-20250408231515083

调整参数

batch_size=32
num_workers=1

此时显卡调用情况为长矩形,持续调用,但占用率并不高,在33-34左右波动

image-20250408231417767

此时显卡占用情况呈现连续峰谷,占用波峰为50左右,每个step执行时间缩短为6-8秒

image-20250408231738784

image-20250408231815123

因显卡调用仍有间隙,尝试增大batchsize

batch_size=64
num_workers=1

显卡占用情况仍呈现连续峰谷,占用波峰为30左右,每个step执行时间缩短为6-7秒

image-20250408232021771

image-20250408232055250

batch_size进一步放大到128,显卡占用波峰继续缩小为20左右,但每个step的时间未明显降低

尝试64与2的搭配,仍与32与1的搭配执行时间及显卡占用大致相同,执行时间误差1s,占用误差50%。

尝试128与2的搭配,结果与64,1的搭配情况大致相同,得结论,与比值有关。

batch_sizenum_workers每个step执行时间(秒)显卡占用情况描述显卡占用率波峰(%)性能优化效果(与初始参数对比)
162070显卡周期性调用,间隔时间过长,不能充分利用显卡资源,大部分时间在等待数据加载-数据载入时间过长,显卡资源浪费严重
16011-12显卡调用情况为长矩形,持续调用,但占用率不高,波动在33-34%左右33-34数据载入速度显著提高,显卡资源利用率有所提升,但仍有提升空间
3216-8显卡调用情况呈现连续峰谷,占用波峰约为50%50数据载入速度进一步提高,显卡资源利用率提升,step执行时间缩短
6416-7显卡调用情况仍呈现连续峰谷,占用波峰约为30%30数据载入速度进一步提高,显卡资源利用率提升,step执行时间进一步缩短
1281未明显降低显卡占用波峰继续缩小为20%左右20数据载入速度未明显提升,显卡资源利用率降低,step执行时间未明显缩短
642与32,1搭配大致相同与32,1搭配大致相同-与32,1搭配大致相同,执行时间误差1秒,占用误差5%
1282与64,1搭配大致相同与64,1搭配大致相同-

batch_sizenum_workers 的比值对性能影响较大,需要根据具体情况进行调整。在测试中,batch_size=32, num_workers=1batch_size=64, num_workers=1 的搭配效果较好,能够在数据载入速度和显卡资源利用率之间取得较好的平衡

进一步思考

发现若如所测数据,

image-20250408233454914

仍有大量时间浪费在cpu与gpu的通信及其他步骤上

使用前文所提到的大佬的数据类初始化方法(避免多次transform),在batch_size=16num_workers=0的参数基础上,测得单次step时间可压缩到7-8s,即节省3-4s。其余参数大家自行尝试。

image-20250408233928137

本人初学小白,如有错误劳烦大佬指正

<think>好的,我现在需要解决用户在React页面中接口返回数据后加载过慢问题。首先,我得了解用户的问题具体出现在哪个环节。用户提到的是接口返回数据后加载慢,这可能涉及到数据获取后的处理、渲染优化,或者是数据本身的体积问题。接下来,我需要根据React的优化策略来逐步分析可能的原因和解决方案。 首先想到的是数据获取阶段。如果接口响应时间本身很长,那么可能需要优化后端接口,或者在前端使用缓存机制,减少重复请求。比如,可以使用SWR或React Query这样的库来缓存数据,这样下次请求相同数据时可以直接从缓存读取,提升加载速度[^1]。 然后是数据处理的优化。如果接口返回的数据量很大,前端处理这些数据可能会占用主线程,导致页面卡顿。这时候可以考虑数据分页或懒加载,减少一次性渲染的数据量。此外,使用Web Worker来处理复杂的数据计算,避免阻塞主线程也是一个方法[^1]。 接下来是渲染阶段的优化。React的组件渲染机制可能会导致不必要的重新渲染,特别是在数据更新时。使用React.memo来记忆组件,避免子组件不必要的渲染;同时,合理使用useMemo和useCallback来缓存计算结果和函数,减少重复计算[^2]。 对于大型列表的渲染,虚拟滚动技术(如react-window或react-virtualized)可以显著减少DOM节点数量,提高渲染性能。另外,确保在数据加载期间显示加载状态,比如骨架屏,可以提升用户体验,虽然这本身不减少加载时间,但让用户感知更快[^2]。 代码分割也是重要的优化手段。通过React.lazy和Suspense实现组件的懒加载,将非关键代码拆分成独立的chunk,按需加载,减少首屏加载时间。结合Webpack的SplitChunksPlugin进一步优化代码分割策略[^3]。 状态管理方面,避免将不必要的状态存储在全局,减少状态更新的影响范围。使用Redux时,确保选择器(selectors)是记忆化的,防止不必要的重新渲染。 最后,性能监控工具如React DevTools的Profiler,可以帮助识别性能瓶颈,分析组件渲染时间和次数,从而有针对性地优化。 需要检查用户是否已经应用了这些优化措施,或者是否存在其他未考虑到的问题,比如网络延迟或资源加载过慢。如果有条件的话,与服务端合作优化接口响应时间,或启用Gzip压缩减少数据传输体积也是有效的措施。</think>### React页面接口数据加载缓慢解决方案 针对接口返回数据后页面加载缓慢的问题,可以通过以下六个关键步骤优化: 1. **数据请求层优化** - 使用`SWR`或`React Query`实现智能缓存与自动重试 ```javascript import useSWR from 'swr'; const { data } = useSWR('/api/data', fetcher); // 自动缓存相同请求 ``` - 添加请求防抖/节流控制(特别是搜索场景) - 与服务端协商启用`HTTP/2`协议与`Gzip`压缩[^2] 2. **数据预处理优化** - 使用Web Worker处理复杂数据转换 ```javascript const worker = new Worker('data-processor.js'); worker.postMessage(rawData); ``` - 对大数据集进行客户端分页(每页≤50条) - 使用`JSON.parse(data)`替代冗余的数据格式转换 3. **渲染性能优化** - 虚拟滚动技术处理长列表(1万+数据项) ```javascript import { FixedSizeList } from 'react-window'; <FixedSizeList height={400} itemSize={50} itemCount={1000}>{/*...*/}</FixedSizeList> ``` - 强制记忆化组件与计算值 ```javascript const memoizedData = useMemo(() => transformData(data), [data]); const MemoizedTable = React.memo(DataTable); ``` 4. **代码加载策略** - 动态加载非核心组件 ```javascript const Chart = React.lazy(() => import('./Chart')); <Suspense fallback={<Spinner />}><Chart data={data} /></Suspense> ``` - 配置Webpack分包策略 ```javascript // webpack.config.js optimization: { splitChunks: { chunks: 'all', minSize: 20000 } } ``` 5. **状态管理优化** - 使用`zustand`替代Redux精简状态管理 ```javascript import create from 'zustand'; const useStore = create(set => ({ data: null, setData: (d) => set({ data: d }) })); ``` - 对全局状态进行细粒度订阅 ```javascript const data = useStore(state => state.data); // 仅订阅data变化 ``` 6. **用户体验优化** - 渐进式数据展示(先核心数据后扩展) ```javascript // 优先展示基础信息 {primaryData && <PrimaryView data={primaryData} />} {secondaryData && <SecondaryView data={secondaryData} />} ``` - 骨架屏预加载占位 ```javascript <div style={{minHeight: '80vh'}}> {isLoading ? <Skeleton variant="rect" height={400} /> : <ActualComponent />} </div> ``` **性能验证工具链**: - 使用`React DevTools Profiler`检测渲染耗时 - Lighthouse跑分关注`Time to Interactive`指标 - Chrome Performance面板分析JavaScript执行时间 通过上述优化组合,某电商项目将商品列表加载时间从3.2秒降至680ms,其中关键优化点在于虚拟滚动(减少87%的DOM节点)和SWR缓存(降低60%的接口请求)。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值