2024年1月

基础篇、实战篇、源码篇、面试篇四大篇章带你系统掌握 Next.js!

前言

欢迎学习 Next.js!在学习具体的知识点之前,我们先来创建一个 Next.js 项目。创建了可运行的项目,才能在学习的时候边调试边理解,从而达到事半功倍的效果。

幸运的是,Next.js 提供了开箱即用的
create-next-app
脚手架,内置支持 TypeScript、ESLint 等功能,零配置即可实现自动编译和打包。

本篇我们会讲解创建项目的两种方式:自动创建项目和手动创建项目,以及开发项目时常用的脚本命令。同时我们会对脚本背后的
next
命令进行详解,帮助大家了解每个命令实现的功能以及可选参数。

1. 自动创建项目

1.1. 环境要求

此本小册基于的是目前最新版本的 v14 版本,需要
Node.js 18.17
及以后版本,支持 macOS、Windows、Linux 系统。

1.2. 创建项目

最快捷的创建 Next.js 项目的方式是使用
create-next-app
脚手架,你只需要执行:

npx create-next-app@latest

接下来会有一系列的操作提示,比如设置项目名称、是否使用 TypeScript、是否开启 ESLint、是否使用 Tailwind CSS 等,根据自己的实际情况进行选择即可。如果刚开始你不知道如何选择,遵循默认选择即可,这些选择的作用我们会随着小册的学习逐渐了解。

注:为了减少展示的代码量,此本小册的示例代码并未使用 TypeScript。(想学习 TypeScript 的同学可以看我
整理的最新的 TypeScript 官方文档

image.png

完成选择之后,
create-next-app
会自动创建项目文件并安装依赖,创建安装完的项目目录和文件如下:

image.png

如果你不使用
npx
,也支持使用
yarn

pnpm

bunx

yarn create next-app
pnpm create next-app
bunx create-next-app

1.3. 运行项目

查看项目根目录
package.json
文件的代码:

// package.json
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},

我们可以看到执行命令有
dev

build

start

lint
,分别对应开发、构建、运行、代码检查。

开发的时候使用
npm run dev
。部署的时候先使用
npm run build
构建生产代码,再执行
npm run start
运行生产项目。运行
npm run lint
则会执行 ESLint 语法检查。

现在我们执行
npm run dev
运行项目吧!

image.png

命令行会提示运行在
3000
端口,我们在浏览器打开页面
http://localhost:3000/
,看到如下内容即表示项目成功运行:

image.png

注:学习的时候为了避免浏览器插件带来的影响,建议在无痕模式下测试。

1.4. 示例代码

Next.js 提供了丰富的示例代码,比如
with-redux

api-routes-cors

with-electron

with-jest

with-markdown

with-material-ui

with-mobx
,从这些名字中也可以看出,这些示例代码演示了 Next.js 的各种使用场景,比如
with-redux
就演示了 Next.js 如何与 redux 搭配使用。

你可以访问
github.com/vercel/next…
来查看有哪些示例代码。如果你想直接使用某个示例代码,就比如
with-redux
,无须手动 clone 代码,在创建项目的时候使用
--example
参数即可直接创建:

npx create-next-app --example with-redux your-app-name

注:使用示例代码的时候,并不会像执行
npx create-next-app
时提示是否使用 TypeScript、ESLint 等,而是会直接进入项目创建和依赖安装。

2. 手动创建项目

大部分时候我们并不需要手动创建 Next.js 项目,但了解这个过程有助于我们认识到一个最基础的 Next.js 项目依赖哪些东西。

2.1. 创建文件夹并安装依赖

现在,创建一个文件夹,假设名为
next-app-manual

cd
进入该目录,安装依赖:

npm install next@latest react@latest react-dom@latest

npm 会自动创建
package.json
并安装依赖项。

2.2. 添加 scripts

打开
package.json
,添加以下内容:

{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
}
}

2.3. 创建目录


next-app-manual
下创建一个
layout.js

page.js
文件:

// app/layout.js
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
// app/page.js
export default function Page() {
return <h1>Hello, Next.js!</h1>
}

2.4. 运行项目

现在运行
npm run dev
,正常渲染则表示运行成功:

image.png

3. Next.js CLI

通过
package.json
中的代码我们知道:当我们运行
npm run dev
的时候,其实执行的是
next dev

next
命令就是来自于 Next.js CLI。Next.js CLI 可以帮助你启动、构建和导出项目。

完整的 CLI 命令,你可以执行
npx next -h
查看(
-h

--help
的简写)。

image.png

从上图可以看到,
next
可以执行的命令有多个,我们介绍下最常用的一些。

注:因为我们是使用
npx
创建的项目,这种方式下避免了全局安装
create-next-app
,所以我们本地全局并无
next
命令。如果你要执行
next
命令,可以在
next
前加一个
npx
,就比如这次用到的
npx next -h

3.1. next build

执行
next build
将会创建项目的生产优化版本:

npx next build

构建输出如下:

image.png

从上图可以看出,构建时会输出每条路由的信息,比如 Size 和 First Load JS。注意这些值指的都是 gzip 压缩后的大小。其中 First Load JS 会用绿色、黄色、红色表示,绿色表示高性能,黄色或红色表示需要优化。

这里要解释一下 Size 和 First Load JS 的含义。正常我们开发的 Next.js 项目,其页面表现类似于单页应用,即路由跳转(我们称之为“导航”)的时候,页面不会刷新,而会加载目标路由所需的资源然后展示。

加载目标路由一共所需的 JS 大小 = 每个路由都需要依赖的 JS 大小 + 目标路由单独依赖项 JS 大小

其中:

  • 加载目标路由一共所需的 JS 大小就是
    First Load JS
  • 目标路由单独依赖项 JS 大小就是
    Size
  • 每个路由都需要依赖的 JS 大小就是图中单独列出来的
    First load JS shared by all

也就是说:

First Load JS = Size + First load JS shared by all

以上图中的
/
路由地址为例,89 kB(First Load JS)= 5.16 kB(Size) + 83.9 kB(First load JS shared by all)

使用官方文档中的介绍:

  • Size
    :导航到该路由时下载的资源大小,每个路由的大小只包括它自己的依赖项
  • First Load JS
    :加载该页面时下载的资源大小
  • First load JS shared by all
    :所有路由共享的 JS 大小会被单独列出来

现在我们访问生产版本的
http://localhost:3000/

截屏2023-12-04 下午3.38.18.png

上图中红色框住的 JS 是每个页面都要加载的 JS,根据命令行中的输出,总共大小为
83.9
kB,
413-dd2d1e77cac135ea.js

page-9a9638f75b922b0c.js
是这个页面单独的 JS,总共大小为
5.16
kB,所有JS 资源大小为
89 kB
。(注:跟图中的数字没有完全一致是因为没有开启 gzip 压缩)

next build --profile

该命令参数用于开启 React 的生产性能分析(需要 Next.js v9.5 以上)。

next build --profile

然后你就可以像在开发环境中使用 React 的
profiler
功能。

如果你想测验这个功能,首先你的
浏览器要装有 React 插件
,然后你要对 React 的
Profiler API
有一定了解(其实就是测量组件渲染性能)。比如现在我们把
page.js
的代码改为:

// app/page.js
import React from 'react'
export default function Page() {
return (
<React.Profiler id="hello">
<p>hello app server</p>
</React.Profiler>
)
}

执行
npm run dev
,你在控制台里可以看到:

image.png

通常执行
npm run build

npm run start
后,你再打开控制台,会发现在生产环境中不支持性能测量:

image.png

但如果你执行
npx next build --profile
再执行
npm run start
,尽管 React 插件会显示当前在生产环境,但 Profiler 是可以使用的:

image.png

image.png

这个功能可以帮助大家排查线上的性能问题。

next build --debug

该命令参数用于开启更详细的构建输出:

next build --debug

开启后,将输出额外的构建输出信息如
rewrites

redirects

headers

举个例子,我们修改下
next.config.js
文件:

/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
async redirects() {
return [
{
source: '/index',
destination: '/',
permanent: true,
},
]
},
async rewrites() {
return [
{
source: '/about',
destination: '/',
},
]
}
}
module.exports = nextConfig

再执行
npx next build --debug
,输出结果如下:

image.png

你可以看到相比之前的构建输出信息,多了
rewrites

redirects
等信息。

3.2. next dev

开发模式下,使用
next dev
运行程序,会自动具有热加载、错误报告等功能。默认情况下,程序将在
http://localhost:3000
开启。如果你想更改端口号:

npx next dev -p 4000

如果你想更改主机名(hostname):(以便其他主机访问)

npx next dev -H 192.168.1.2

3.3. next start

生产模式下,使用
next start
运行程序。不过要先执行
next build
构建出生产代码。运行的时候,跟开发模式相同,程序默认开启在
http://localhost:3000
。如果你想更改端口号:

npx next start -p 4000

3.4. next lint

执行
next lint
会为
pages/

app/

components/

lib/

src/
目录下的所有文件执行 ESLint 语法检查。如果你没有安装 ESLint,该命令会提供一个安装指导。如果你想要指定检查的目录:

next lint --dir utils

3.5. next info

next info
会打印当前系统相关的信息,可用于报告 Next.js 程序的 bug。在项目的根目录中执行:

next info

打印信息类似于:

Operating System:
Platform: linux
Arch: x64
Version: #22-Ubuntu SMP Fri Nov 5 13:21:36 UTC 2021
Binaries:
Node: 16.13.0
npm: 8.1.0
Yarn: 1.22.17
pnpm: 6.24.2
Relevant packages:
next: 12.0.8
react: 17.0.2
react-dom: 17.0.2

这些信息可以贴到 GitHub Issues 中方便 Next.js 官方人员排查问题。

小结

恭喜你,完成本篇内容的学习!

这一节我们讲解了
自动创建项目

手动创建项目
两种创建项目的方式,如果是全新的项目,推荐使用自动创建方式。如果是项目中引入 Next.js,可以参考手动创建项目的方式。

Next.js 项目常用的脚本有三个:
npm run dev
用于开发时使用、
npm run build
用于构建生产版本、
npm run start
用于运行生产版本。


package.json
中,我们得知这些脚本背后用的其实是 Next.js CLI 的
next
命令,然后我们对常用的
next
命令和相关参数进行了介绍。在必要的时候,可以使用这些命令和参数自定义 npm 脚本。

靡不有初,鲜克有终。恭喜你迈出第一步!接下来我们将进入路由篇,带大家了解 Next.js v13 带来颠覆式更新的的 App Route 功能。在学习的过程中,如果遇到有疑问的地方,一定要多写 demo 测试哦!

知识星球【Next.js开发指南】(已更新至第33章)

  1. 初始篇 | Next.js CLI
  2. 路由篇 | App Router
  3. 路由篇 | 动态路由、路由组、平行路由和拦截路由
  4. 路由篇 | 路由处理程序和中间件
  5. 路由篇 | 国际化
  6. 数据获取篇 | 数据获取、缓存与重新验证
  7. 数据获取篇 | Server Actions 与表单
  8. 渲染篇 | 从 CSR、SSR、SSG、ISR 开始说起
  9. 渲染篇 | 服务端组件和客户端组件
  10. 渲染篇 | Streaming 和 Edge Runtime
  11. 缓存篇 | Caching
  12. 样式篇 | Tailwind CSS、CSS-in-JS 与 Sass
  13. 组件篇 | Images
  14. 组件篇 | Font
  15. 组件篇 | Link 和 Script
  16. 优化篇 | 懒加载
  17. 配置篇 | TypeScript 和 ESLint
  18. 配置篇 | 环境变量、路径别名与 src 目录
  19. 配置篇 | MDX
  20. 配置篇 | 草稿模式和内容安全策略
  21. 配置篇 | 路由段配置项
  22. 部署篇 | 静态导出
  23. Metadata 篇 | 基于配置
  24. Metadata 篇 | 基于文件
  25. API 篇 | next.config.js(上)
  26. API 篇 | next.config.js(下)
  27. API 篇 | 请求相关的常用函数与方法
  28. API 篇 | 常用函数与方法
  29. 实战篇 | React Notes | 项目介绍与创建
  30. 实战篇 | React Notes | 侧边栏笔记列表
  31. 实战篇 | React Notes | 笔记预览界面
  32. 实战篇 | React Notes | 笔记编辑界面
  33. 实战篇 | React Notes | 笔记搜索
  34. 实战篇 | React Notes | 国际化
  35. 实战篇 | React Notes | Auth
  36. 实战篇 | React Notes | 文件上传
  37. 实战篇 | React Notes | 部署(一)
  38. 实战篇 | React Notes | 部署(二)
  39. 实战篇 | 博客 | 项目创建
  40. 实战篇 | 博客 | 博客后台
  41. 实战篇 | 博客 | MDX
  42. 实战篇 | 博客 | Server Actions
  43. 实战篇 | 博客 | 渲染原理
  44. 实战篇 | App | 需求分析
  45. 实战篇 | App | 数据库设计
  46. 实战篇 | App | 项目创建
  47. 实战篇 | App | 移动端处理
  48. 实战篇 | App | 接口开发
  49. 实战篇 | App | 数据请求
  50. 实战篇 | App | 构建部署
  51. 源码篇 | 源码架构
  52. 源码篇 | 调试代码
  53. 源码篇 | 路由实现
  54. 源码篇 | 渲染原理
  55. 源码篇 | 手写 SSR
  56. 源码篇 | mini-next
  57. 源码篇 | mini-next
  58. 源码篇 | mini-next
  59. 源码篇 | mini-next
  60. 面试篇 | 常见面试题及解析
  61. 面试篇 | 常见面试题及解析
  62. 面试篇 | 常见面试题及解析

如果需要了解其他图像处理的文章,请移步小编的GitHub地址

传送门:请点击我

如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice

VisionPro有很多的示例和算子,这里展示如何使用VisionPro,即如何搭建QuickBuild示例工程。我自己的笔记不会按照顺序一一展示出来的,也许那个文章先OK,我会先release出来的。 其中大部分的图片和步骤都是VisionPro的官方文档,我这里只是自己的学习笔记,不做任何商用。

1,QuickBuild 使用简介

VisionPro是全球领先的计算机式视觉软件。它主要用于设置和部署视觉应用,无论是使用相机还是图像采集,只需要借助VisionPro的QuickBuild就可以执行各种功能,包括几何对象定位和检测,识别,测量和对准。

VisionPro QuickBuild是VisionPro安装包中的一个多功能应用程序,允许我们进行原型设计和构建全面的视觉解决方案。它提供了获取图像、使用各种视觉工具进行分析以及评估对象检测质量的结果的功能。
以下是我使用VisionPro QuickBuild后的总结:
  1. 启动QuickBuild
    :通过Windows开始菜单下的Cognex->Cognex VisionPro 10.0->VisionPro 10.0->QuickBuild或使用Windows桌面上的QuickBuild图标启动。
  2. 工作区概览
    :打开QuickBuild时,它会呈现一个未保存的工作区,用于创建新应用程序。
  3. 配置图像采集设备
    :在QuickBuild中,您可以配置图像采集设备或将文件(或文件目录)添加到工作区。
  4. 创建和管理ToolBlocks
    :您可以创建新的ToolBlock或将已保存的ToolBlock加载到工作区。
  5. 访问已保存的工作区
    :QuickBuild还提供对已保存的工作区和可能从Cognex网站下载的示例工作区的访问。
  6. 交互式应用程序构建器
    :QuickBuild允许您定义包含多个作业的应用程序。对于每个作业,您可以定义和配置图像来源,添加视觉工具,并设置结果分析逻辑。
  7. 全面的视觉工具
    :VisionPro以其广泛的功能性而闻名,包括从几何对象定位和检查到识别、测量和对齐,以及特定于半导体和电子行业的专业功能。
有关使用VisionPro QuickBuild的详细说明和更多信息,请参考Cognex的支持页面及其广泛的文档。提供的资源将使你深入了解如何有效地利用QuickBuild应用程序来实现视觉解决方案。我这里只是简单的介绍,也是加深自己学习的印象。

2,QuickBuild 操作简介

VisionPro 安装包括 QuickBuild,这是一个允许您制作原型和构建完整视觉解决方案的应用程序。您可以采集图像,使用各种视觉工具对其进行分析,并检查结果以确定被检查对象的质量。您的应用程序可以使用多个相机来响应各种触发类型,或者可以使用图像数据库。

2.1  界面介绍

通过 Windows 开始菜单 (
Cognex->Cognex VisionPro10.1
->
VisionPro 10.1
->
QuickBuild
) 或 Windows 桌面上的 QuickBuild 图标。

默认情况下,QuickBuild 会打开一个未保存的工作区来创建新应用程序,默认 QuickBuild 工作区支持带有类似方法的
工作区资源管理器

主页
选项卡,用于检测连接的相机、查找图像数据库以及将视觉工具添加到您的应用程序:

左侧的工作区浏览器支持启动新视觉解决方案的选项:

QuickBuild 主页选项卡提供了类似的选项

1. 配置图形采集设备或向此工作区域添加文件(或文件目录)

2. 创建新的ToolBlock 或将保存的 ToolBlock 加载到此工作区

您可以随时取消停靠或关闭
主页
选项卡。要再次启用
主页
选项卡,请单击按钮栏中的图标:

在开发应用程序时,您将向工作区添加更多选项卡。单击并按住一个选项卡可根据需要将其拖离工作区。

2.2 相机采集操作

在安装VisionPro软件之前或之后,将GigE Vision相机连接到计算机。有关将 GigE Vision 相机连接到 GigE Vision Cognex 图像采集卡的详细信息,请参阅 VisionPro 文档安装程序随附的 CFG-8700 系列硬件手册。

执行以下步骤从 GigE Vision 相机采集图像:

1. 启动 QuickBuild 并选择
工具->GigE 配置器
启动 GigE Vision 配置工具

使用配置工具为图像采集卡上的每个 GigE Vision 网络适配器以及与其相连的 GigE Vision 相机分配 IP 地址。

  1. 转到工作区资源管理器并单击
    采集
    中的“+”图标:
  1. 使用添加设备对话框以选择要使用的已连接相机:
QuickBuild 打开一个用于配置采集设置的新选项卡:

QuickBuild 尝试为与此相机关联的 ToolBlock 创建先进先出 (FIFO) 采集队列并采集图像。如果成功,该选项卡会显示其他选项卡以根据需要设置其他图像采集属性:

2.3  图形数据库采集操作

QuickBuild支持从图形数据库中采集图形,您可以添加对任意数量数据库的引用,并稍后将他们分配给ToolBlock。

1. 启动QuickBuild,导航到工作区浏览器并单击“+” 图片数据库:

2. 使用选择图形数据库对话框选择 .cdb 或者 .idb 图像数据库。当然也可以选择各种格式的图像,比如jpg, png, jpeg, bmp等,也可以直接选择整个图像的文件夹。

3. 工作区浏览器列出了对您添加到此 QuickBuild 应用程序的图像数据库的所有引用:

每个图像数据库都可以与不同的视觉工具 ToolBlock 相关联。

2.4 添加ToolBlock

1. 要将 ToolBlock 添加到您的 QuickBuild 应用程序,请转到工作区资源管理器并单击
视觉
中的“+”图标:
2. QuickBuild 中出现一个新的 ToolBlock:
3. 使用工作区资源管理器和工作区选项卡之间的灰色条选择此 ToolBlock 的图像源:

2.4.1. 将视觉工具添加到 ToolBlock

1. 单击
工具面板
显示一个 ToolBlock,它支持视觉工具的 Toolbox 分析采集的图像:
2. 双击视觉工具将其添加到当前 ToolBlock。将图像源拖放到任何将分析采集图像的视觉工具中:
3. 按钮栏提供了两个按钮来执行 ToolBlock 中的所有视觉工具:

2.4.2 使用多个ToolBlock

QuickBuild 支持在您的视觉应用程序中使用多个 ToolBlock,将一个视觉工具生成的输出图像传递给另一个 ToolBlock 以进行额外分析。

例如,以下 ToolBlock 从固定工具获取输出图像并将其传递给第二个 ToolBlock:

第二个 ToolBlock 可以分析固定工具的输出图像:

2.5 添加脚本

QuickBuild 支持向任何 ToolBlock 添加脚本。ToolBlock 脚本允许您自定义和扩展 ToolBlock 包含的任何视觉工具的功能,或向视觉工具生成的结果添加额外的逻辑。
要将脚本添加到任何 ToolBlock,请单击脚本图标:
使用C#语言在 Microsoft.Net 下编写 ToolBlock脚本。

3 QuickBuild 用户文档简介

您的 VisionPro 安装包括可从单个 Web 界面获取的用户文档。通过 Windows 开始菜单 (
Cognex->Cognex VisionPro10.0
->
VisionPro 10.0用户文档
)。
出现用户文档的 Web 界面:
单击任何标题将其打开。但是这里推荐使用英文文档,因为在使用的过程中,我发现英文文档比较全面,而且部分算子中文文档并没有更新。

英文文档点击进入如下:

比如我们要查看图像转换算子:

1、二叉树定义

mark

2、二叉树存储结构

mark

2.1、经典题目代码构建

mark

代码构建:
mark

代码对应的二叉树的图:
mark

一行代码搞定lettcode2236,运行通过;就是考察对二叉树结构的理解:
mark

3、深度优先遍历DFS和广度优先遍历BFS概念

mark

3.1、深入讲解广度优先遍历BFS

mark

树的
广度优先遍历BFS
也可以称之为
层序遍历

mark

mark

队列基础知识
mark

4、万能模板经典题

mark

4.1、LeetCode102

mark

mark

mark

mark

4.2、LeetCode107

和102题相同的模板,代码几乎相同,只需要在最后一行用切片的写法做一个反转即可:
mark

4.3、LeetCode103

题目:
mark

题意:
mark

题解:
只需要在模板的基础上,添加一个Flag标志,标记从左往右或者从右往左即可。
mark

4.4、LeetCode637

这连续几道题,都提到二叉树的

的概念,就可以很明显的考虑到是要用
层序遍历
来做。
题目:
mark

题意:
mark

题解:
基于模板,最后添加元素处改一下,由添加层列表,即(每一层的所有节点),改为添加每一层所有节点的平均值即可。
mark

4.5、LeetCode199

题目:
mark

题意:
mark

题解:
根据题意,实际上这道题问的是每一

的最右边的元素是什么?
所以还是涉及到

的概念,还是要用
层序遍历
来做。然后再每一层取出最右边的元素即可。

基于模板,只改一下最后的添加,由添加层列表,改为添加每一层的最后一个元素即可。
mark

如果不用模板,不用层列表sublist,也可以修改为如下代码:
mark
这样就不用额外的空间去存每一层的所有节点。只在每一层的最后一个节点去判断,然后添加最后一个节点到总的列表。

这道题,不是一个明显的层序遍历的题,但是仔细分析题意,思路转换,还是能结合层序遍历模板来解题的。

4.6、LeetCode513

题目和题意:
mark

题解:
基于模板,只需要改动最终的返回ans,ans的初始化由初始化为list改为初始化为root.val,即初始化为根节点的值。
ans的返回由添加层列表,改为添加层的左侧第一个元素的值。
mark

考虑内存空间的情况,可以进一步优化为如下代码:
1和2都可以解决问题
1、
mark
2、
mark

mark

4.7、LeetCode515

题目和题意:
mark

题解:
模板改最后一行添加层列表的最大值即可。
mark

4.8、LeetCode1161

题目和题意:
这个题目还是需要仔细读一下的:
mark

题解:
1、先解决层号的问题,输出层号
mark

mark

2、题解完成:
mark

考虑到节点值可能为负数的情况,最大层的和level_max_sum的初始化,由初始化为0改为初始化为负无穷-inf或者初始化为第一层的值root.val
mark

mark

对题解优化,尽量不要用标准sum函数api,因为它每次也要全部遍历,比较耗时。
不用sum函数的修改版:
mark

4.9、LeetCode101

题目和题意:
示例1
mark
示例2
mark

题解:
1、
mark

2、题解1中还是有问题,满足示例1图的情况,但是不满足示例2;
修改为如下代码后,同时满足示例1和示例2
mark

4.10、LeetCode1302

题目:
mark

题意:
最深的那层这里就是第四层的7和8、最深的那层的节点就一定是叶子节点。

mark

mark

题解:
修改 4.6、LeetCode513 中的代码,将找左下角节点的值,改为求和即可。
mark

不用sum函数的优化版:
mark

5、总结

最核心知识点:
BFS与队列的关系
mark

leetcode102题引申出的万能模板:
mark

mark

6、练习题

mark


注:
文中截图源自大佬:
闭着眼睛学数理化
课程内容

前言

大伙既然都来做这个了,那配个CUDA环境肯定是必不可少的了吧(笑)

最前面的最前面,

流程

  1. 确定当前设备支持的CUDA版本
  2. 安装CUDA Toolkit 和 GPU版的Paddlepaddle
  3. 下载cuDNN Archive
  4. 手动放置配套的cuDNN到指定文件夹
  5. 测试

1.确定当前设备支持的CUDA版本

当然了,我这里默认了你是有安装NVIDIA驱动的,如果没有,你可以自己百度一下如何安装NVIDIA驱动,或者直接下载一个Geforce experience来更新驱动。

首先右键桌面,点击NVIDIA控制面板

在这里插入图片描述
在NVIDIA控制面板下面,点击系统信息

在这里插入图片描述

下图中点击组件
在这里插入图片描述
可以在3D设置中看到自己当前支持的CUDA版本,比如我这里是12.3.107

在这里插入图片描述

2.安装CUDA Toolkit

在安装前,我希望你确定一件事,这里我们找到paddlepaddle官方网站的安装界面,这里是有这么一句话:
在这里插入图片描述

我这里最高能用CUDA 12.0版本,那么我们就需要配合cuDNN v8.9.1版本使用,还需要搭载TensorRT 8.6.1.6

我先说明,你在使用paddle的时候,请先下载最基本的CPU版本,然后再安装GPU版本,貌似GPU版本是CPU版本的一个插件一样而不是一个单独可以使用的库。

至于安装命令,可以参考

paddle官网

这里由于是12.0的CUDA版本,所以我这里命令是
在这里插入图片描述

python -m pip install paddlepaddle-gpu==2.6.0.post120 -f https://www.paddlepaddle.org.cn/whl/windows/mkl/avx/stable.html

其次,下载CUDA的链接如下:

CUDA Toolkit Archive

在此链接中找到我们心仪的12.0版本,进行下载
在这里插入图片描述
在这里插入图片描述

CUDA ToolKit就随便安装一下就可以了,直接一直点下一步即可。

3.下载cuDNN Archive

还记得吗,因为我们的CUDA版本为12.0,所以我们现在需要下载的cuDNN版本为v8.9.1

现在找到cuDNN的下载地址:

cuDNN Archive

这里需要登陆NVIDIA官方,可能需要梯子

在这里插入图片描述
这里因为我们是12.x版本,所以就下载上面这个cuDNN版本

4. 手动放置配套的cuDNN到指定文件夹

ok我们现在下好了这个cuDNN包,然后里面是这些东西
在这里插入图片描述

这几个文件夹待会要用,现在先找到环境变量,找到这几项:;
在这里插入图片描述

因为我们是12.0的版本,所以我们转到这个12.0的目录,然后把cuDNN包里面这几个文件夹直接复制进去

在这里插入图片描述

5.测试吧!

测试只需要输入代码如下即可:

import paddle

paddle.utils.run_check()

 # 开启0号GPU训练
use_gpu = True
paddle.device.set_device('gpu:0') if use_gpu else paddle.device.set_device('cpu')

如果看到代码没报错,有如下字样,则代表设备初始化成功,库的导入成功啦!

在这里插入图片描述

数据库故障是不可避免的,任何软件,无论是开源类还是商业类,只要是人创造的,就一定会存在产品缺陷(bug),软件越复杂,承载任务越繁多,触发bug的概率就越大,这是IT人的基本常识。

快速定位能力的关键性

真正重要的是,在出现故障时,如何迅速而有效地应对故障,定位故障根因并给出有效的解决方案,这才是确保业务连续性和稳定性的关键。也是决定一款数据库是否成熟的一项关键指标。

可是,也不知道当下风气是怎么了,好多人吧,不踏下心来好好研究自家产品,反而喜好打听别家谁出了啥故障,打听到后就跟中了彩票一样兴奋,之后就开始大作文章,跟客户直接说这产品不行。不晓得这些人是纯粹的天真,不知道这个道理,还只是为了各自利益,揣着明白装糊涂呢?

聊到数据库的故障,这里先抛开其他除数据库本身之外进而引发数据库故障的复杂情况不说,也暂不去讨论因用户操作使用不当这类导致的故障,就只是单纯的聊下所谓很严重的产品本身bug导致的故障。

为了客观,避免有些人又喜欢去对号入座,我们就以业界公认领先的,各方面指标均很优秀的商业数据库产品Oracle来举例,因为它本身承载着当今世界众多重要客户的核心系统,这些人总不能去喷Oracle这款数据库产品也不行吧。

Oracle产品本身bug多么?

Oracle产品本身bug多么?

其实真的很多。

但凡你有在生产环境部署过Oracle数据库,应用过PSU/RU补丁集,就会发现光是建议应用的这些补丁集列表中的bug就非常多,opatch lsinventory 列出的bug号码都能铺满好几页屏幕。

可是,因这些产品bug导致的故障多么?

如果单拎出来某一个客户来讲,其实是不多的,甚至还存在许多自使用以来从未遇到任何软件bug导致故障的幸运客户,尤其一些IT建设比较薄弱的客户,虽然购买了Oracle,但也没打啥补丁,甚至一直连MOS都没登录过,压根儿就没遇到任何产品bug引发的问题。

但是每个bug其实都直接或间接的对应了某个场景下的故障,那这么多隐秘的bug在测试时都没发现,最终又都是咋发现的呢?
反而是因为Oracle太流行,用户太多太广了,开头也提到了,bug这东西本身触发概率并不高,再举个量化的例子,比如说某个bug只有万分之一的概率被用户触发,也就是说1万个用户里面估计也只有一个人能有幸遇到,于是他遇到过提交给官方,出补丁,其他客户定期更新补丁集,就不会再遇到这个bug。

另外,如此庞大复杂的软件其实bug有很多的,但因为你这个场景遇到了A bug,我这个场景遇到了B bug,他那个场景遇到了C bug... 不断完善,你要是想成为全球第一个遇到某个bug的用户,其实都不太容易呢,所以产品稳定性得到了保障。

如果你的IT管理很有章程,按照官方的建议,定期更新推荐的补丁集,实际上就很难遇到bug带来的影响;即使有的客户因各种原因没有及时应用推荐的补丁集,某一天好巧不巧的触发了某个bug,基本MOS一查现象,也大概率会是已知bug,别人早就遇到了,补丁都是现成的,你只需要及时应用这个补丁即可解决。

小概率事件就可以忽略吗?

既然这样,那用户真的就可以无为而治,万无一失了吗?

也不是,小概率事件不等价于不可能发生事件,为了万无一失,还是要确保你所使用的版本在支持周期之内。这也是为什么有的用户讲我不用你新版本的new feature,为啥也要跟着升级版本的原因之一。

很多人会抱着侥幸心理觉得无所谓,自己不会那么倒霉,但一旦真的不幸遇到就会痛苦不堪。

这里再举个实际的例子吧,比如最近就遇到了一个case,简单说的确是因为产品本身bug导致的故障,现象是ADG的Redo Apply缓慢,这个bug其实也非常隐蔽,因为正常平时延迟都是0,根本发现不了,可运气不好的是,恰好在某个重要保障节点,因为OOM类的原因导致ADG同步被意外终止,且也没有被及时监控到,等用户感知到时,已经有了数小时的延迟,正常情况下,这问题也不大,重新启动同步进程Redo Apply也是很快会追平,可此时不幸的发现追日志的效率异常缓慢,基本相当于延迟多久就追了多久,虽然MOS能查到这个问题,也是一个已知的bug,但更不幸的是,目前在MOS上针对这个bug只有Linux平台的现成补丁,而客户的系统是AIX,并没有找到对应补丁,同时与后台SR进一步确认,确认是真没有,且研发也不会再出这个补丁了。

为什么呢?

因为这是一个老的数据库版本,已经不在支持周期内,研发不会为此提供新的补丁。

好在这个bug不算硬伤,追上这次意外的gap之后就可以保持同步,可风险其实依然存在,在升级之前,我们也只能加强监控,避免类似问题发生影响,并强烈建议尽快把版本升级提上日程。

可能有人会讲,一个已知bug,别的平台都出了补丁,为啥就不能也给出个其它平台的补丁呢?要知道打个one-off的patch是很轻松的事情,但大版本升级可是一个大动作,还要协调应用测试配合,干嘛搞这么复杂呢?

其实这样的策略才是真正的对客户负责,也是很合理的,首先Oracle一直都建议用户要使用当前有效期内的LTS长期支持的版本,这样才能集中更多人来更好的保证你的稳定性,Oracle的LTS其实已经是支持周期非常久的了。

而且,不升级的话,就算研发帮你修复了这个bug,但是后续的风险其实会更大,这种已不在支持周期内的版本,万一下次遇到的bug是非常严重的呢?

数据库有故障怎么了?

最后,回到正题,数据库有故障怎么了?

还是那句话,数据库是一个软件,而且是一款非常复杂的软件,遇到故障是再正常不过的,如何迅速而有效地应对故障,定位故障根因并给出有效的解决方案,这才是确保业务连续性和稳定性的关键。

如果说谁家的数据库产品至今为止,都没有任何产品bug导致的故障案例,那并不代表这个数据库产品有多稳定,反而大概率是这个产品的用户量不够,没有积累到足够量的用户去踩到坑而已。

与其纠结这个无意义的话题,不如多多修炼内功,做些真正的实事。

如果是用户角度,首先要了解如何正确的使用自己选择的这款产品,最起码要能避免一些低级错误引发的故障;要知道即便是Oracle的用户群中也存在这样一波人,就是喜欢不读文档不看MOS,凭着自己的感觉不按官方建议的各种瞎搞,结果在一次次变更中因为理解错误、考虑不周导致故障频发,彷佛用的是一款山寨产品一样,最后埋怨产品不稳定,花大价钱找专家兜底排查,结果发现根因全都是胡搞导致的。

如果是厂商角度,不要怕故障,而是会在每次故障后做好支持服务,积累经验,其实可以参考Oracle的做法,建立类似MOS一样的知识库,提供完善且有实际意义的官方文档,至少确保自己的用户群中,有心学习的人是可以依据官方文档的内容,正确的使用产品、排查常规问题。即便是遇到一些疑难的,诸如产品的bug引发的故障,那也不是黑料,而是不断帮助厂商完善产品的弹药。

当然,现实真正要做到这些都不是容易的事情,但DB这个赛道本就不是容易的。如果没想好,还不如先多多去学习别人先进的经验,而不是自己的产品都没几个用户使用,却忙着去挖别人的“黑料”恶意竞争。