• 走进向量计算:制作 OpenBLAS Docker 预构建产物镜像


    本篇文章,将聊聊如何在容器中完成支持多 CPU 架构(x86、ARM)、多种 CPU 类型(Intel、AMD)的 OpenBLAS 的 Docker 镜像,来让包括 Milvus 在内的,使用 OpenBLAS 的软件的 Docker 镜像构建可以“又稳又快”。

    我会试着在接下来的内容中,持续分享如何让一个拥有着一万多颗“星星”的大型数据库项目的容器构建过程不断提速。

    写在前面

    有阅读过以往内容的同学,应该会记得,我在之前的介绍“Milvus 源码编译安装”的文章中,有提到过“要聊聊如何构建一个可靠、可信赖的 Milvus 容器镜像”。

    之前提到过,因为 Milvus 使用的核心搜索引擎 knowhere 有使用到 OpenBLAS。以及,相信有过本地构建经验、或者参考前面文章“走进向量计算:从源码编译 OpenBLAS”进行过构建的同学,对于 OpenBLAS 项目的构建时间漫长,应该是深有体会的。并且,在不同 CPU 架构(x86、ARM),不同类型 CPU(Intel、AMD)的环境下,OpenBLAS 编译产物也是不同的。

    所以,如果我们想搞定支持多种 CPU 架构的 Milvus 容器镜像,自然要先解决多种架构和类型硬件的 OpenBLAS 在容器内的构建。

    如果我们使用 GitHub Action (免费版),你会发现 CI 跑一天都构建不出来 OpenBLAS 这个基础依赖,即使我们采用 8 Cores 这类常见规格的云服务器,也需要“哼哧哼哧”的跑个一个钟头,这里如果我们使用 docker buildx 来模拟不同硬件的话,很有可能跑 4~5 个钟头不见得有结果(可以参考 CI 中大量跑了一天以上被自动取消的任务)。

    而如果我们使用预构建的方式,临时采用“按需付费”的方式,找一台配置较高的机器,或者利用本地高配置的机器,花十几分钟到半个小时,提前做好预构建产物的编译。那么,之后的构建时间,通常就能够缩短到只需要“几秒钟”了,因为文件复制的计算量非常少。

    所以,想要减少开发和构建 Milvus 所需要的时间,在确定的容器环境中,制作预构建产物来减少重复构建花费的大量时间,就变得十分必要的啦。

    准备工作

    既然是容器环境的产物预构建,那么,我们自然需要先完成 Docker 运行环境的安装,如果你的构建环境中已经安装过了 Docker,那么可以跳过这个小节,阅读后面的内容。

    如果你是桌面运行环境,可以访问官网下载安装文件,如果你使用的是服务端环境,可以参考这篇文章中的“更简单的 Docker 安装”,来完成 Docker 环境的准备。

    当然,如果你没有运行 Linux 系统的设备,使用 macOS 或者在 Windows 中使用虚拟机,也是一样的。

    当然,不同硬件架构能够使用的编译参数是有不同的,所以这里,我们需要根据未来计划运行 Milvus 或其他软件所需要的硬件环境,准备对应的硬件,来完成基础依赖的编译。即使Docker Buildx 只能模拟 CPU 架构来进行 Multi-ARCH 构建,但是却无法模拟 CPU 类型,无法满足不同指令集的硬件产物构建。

    前文中,我们有提到需要构建不止一种产物镜像,简单来说:

    • 我们需要构建出最新和次新 Ubuntu LTS 环境下的软件,包含目前 Milvus 长期使用的 0.3.9 版本,以及未来考虑升级的最新的稳定的版本:0.3.20 。
    • 以及考虑到目前 Milvus 官方镜像还是基于 Ubuntu 18.04,所以构建这个环境下的产物,对于能够平滑替换,进行验证也是必要的。
    • 考虑到目前不仅是云环境,还是本地环境, ARM 芯片和 AMD Zen 架构的 CPU 都越来越多,所以,我们也需要考虑这两个环境下的产物构建。

    当然,因为 OpenBLAS 不同版本,在ARM 芯片、AMD ZEN 架构 CPU 下存在一些兼容问题,即使我们能够得到构建产物,产物其实也并不能够通过软件的单元测试。所以,我们在构建的过程中,会忽略掉构建结果不能 100% 通过测试的“组合”。

    好了,我们先来聊聊最常见的 Intel CPU 的产物构建吧。

    基于 Intel x86 架构 CPU 的容器预构建

    因为不同类型、架构的 CPU,能够构建不同 OpenBLAS 的可靠产物是不同的,所以我们先来明确要构建哪些版本。在 Intel x86 芯片环境下,我们需要满足下面的需求:

    • 最新 Ubuntu LTS 版本 22.04 环境下的两个版本的 OpenBLAS:0.3.9 和 0.3.20,满足未来 Milvus 升级到最新的 Ubuntu LTS 时使用。
    • 上一个 Ubuntu 稳定 LTS 版本 20.04 环境下的 OpenBLAS:0.3.9 和 0.3.20,满足未来 Milvus 能够升级到次新 LTS 版本时使用。
    • 目前 Milvus 官方镜像使用的 Ubuntu LTS 版本 18.04 环境下的 OpenBLAS:0.3.9 和 0.3.20,满足当前版本的 Milvus ,能够平滑切换 OpenBLAS 依赖安装,以及验证最新版本的 OpenBLAS 使用。

    简单来说,就是我们需要分别构建 Ubuntu 18.04~22.04 环境下,0.3.9 和 0.3.20 两个版本的 OpenBLAS 镜像,来满足当前状况的 Milvus、过渡期的 Milvus,以及适合长远的 Milvus 使用的 OpenBLAS 预构建产物。

    设计 Intel CPU 使用的通用 Dockerfile 镜像文件

    即使我们需要根据排列组合做镜像,但可维护性依旧是我们最需要考虑的地方,因此,我们最好是能够使用一个 Dockerfile 文件来管理同 CPU 架构的镜像(按照 CPU 架构拆分镜像):

    # 允许使用参数来动态改变我们所使用的基础镜像
    ARG LTS=22.04
    FROM ubuntu:${LTS} AS Base
    # (示意) 安装必要的依赖
    RUN apt-get update && \
        apt-get install ... && \
        apt-get remove --purge -y
    # 设置工作目录
    WORKDIR /src
    # 允许使用参数来指定 OpenBLAS 的版本,从官方发布页面获取软件源码
    ARG OPENBLAS_VERSION=0.3.9
    ENV OPENBLAS_VERSION=${OPENBLAS_VERSION}
    RUN wget "https://github.com/xianyi/OpenBLAS/archive/v${OPENBLAS_VERSION}.tar.gz" && \
        tar zxvf v${OPENBLAS_VERSION}.tar.gz && rm v${OPENBLAS_VERSION}.tar.gz
    # 改变工作目录
    WORKDIR /src/OpenBLAS-${OPENBLAS_VERSION}
    # (示意) 使用适合 Intel 芯片的参数,进行编译和安装
    RUN make && make install
    
    # 将构建后的产物保存到一个干净的空镜像里,为后续使用做准备
    FROM scratch
    ARG OPENBLAS_VERSION=0.3.9
    ENV OPENBLAS_VERSION=${OPENBLAS_VERSION}
    COPY --from=Base /usr/lib/libopenblas-r${OPENBLAS_VERSION}.so /usr/lib/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    上面是隐藏了一些细节(依赖安装、编译命令)的基础镜像设计,首先根据用户传递的构建参数,来确定要使用的基础 Linux 环境,和要构建的 OpenBLAS 产物版本。然后再将构建完毕的内容,复制到一个崭新的空白容器里,来简化容器复杂度,以及方便后续 Milvus 或其他软件的构建过程使用。

    或许有小伙伴好奇,为什么一定要使用多阶段构建呢。如果我们没有进行多阶段构建,剥离环境和构建产物,那么我们得到的预构建镜像,大概会是下面这样的“壮观”体积。

    soulteary/milvus-openblas     0.3.20-intel-x86-ubuntu-22.04     3.95GB
    soulteary/milvus-openblas     0.3.20-intel-x86-ubuntu-20.04     9.03GB
    soulteary/milvus-openblas     0.3.20-intel-x86-ubuntu-18.04     7.54GB
    soulteary/milvus-openblas     0.3.9-intel-x86-ubuntu-22.04      3.35GB
    soulteary/milvus-openblas     0.3.9-intel-x86-ubuntu-20.04      6.68GB
    soulteary/milvus-openblas     0.3.9-intel-x86-ubuntu-18.04      5.55GB
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    当采用了多阶段构建之后,即使在不进行额外压缩的前提下,产物镜像尺寸也能够得到非常明显的变化:

    soulteary/milvus-openblas     0.3.20-intel-x86-ubuntu-22.04     143MB
    soulteary/milvus-openblas     0.3.20-intel-x86-ubuntu-20.04     318MB
    soulteary/milvus-openblas     0.3.20-intel-x86-ubuntu-18.04     266MB
    soulteary/milvus-openblas     0.3.9-intel-x86-ubuntu-22.04      122MB
    soulteary/milvus-openblas     0.3.9-intel-x86-ubuntu-20.04      241MB
    soulteary/milvus-openblas     0.3.9-intel-x86-ubuntu-18.04      201MB
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    完整文件,我上传到了 GitHub,方便有需要的同学自取:soulteary/docker-openblas/blob/main/intel/Dockerfile

    我们将上面的内容保存为 Dockerfile,就能够正式进行 Intel x86 CPU 环境下的镜像构建了。

    Ubuntu 和 Intel 环境下的 OpenBLAS 构建

    先来处理 Ubuntu 22.04 系统环境下,0.3.9 版本 OpenBLAS 的构建:

    docker build --build-arg=LTS=22.04 --build-arg=OPENBLAS_VERSION=0.3.9 -t soulteary/milvus-openblas:0.3.9-intel-22.04 .
    
    • 1

    执行命令,经过漫长的等待之后,将能够看到类似下面的输出,包含了一大堆“测试通过”的日志信息和容器“构建完毕”的提示:

    ...
    OPENBLAS_NUM_THREADS=2 ./xscblat1
     Real CBLAS Test Program Results
    
    
     Test of subprogram number  1         CBLAS_SDOT     
                                        ----- PASS -----
    
     Test of subprogram number  2         CBLAS_SAXPY    
                                        ----- PASS -----
    ...
     cblas_zsyr2k PASSED THE TESTS OF ERROR-EXITS
    
     cblas_zsyr2k PASSED THE COLUMN-MAJOR COMPUTATIONAL TESTS (  1764 CALLS)
     cblas_zsyr2k PASSED THE ROW-MAJOR    COMPUTATIONAL TESTS (  1764 CALLS)
    
     END OF TESTS
    ...
    make[1]: Leaving directory '/src/OpenBLAS-0.3.9/exports'
    
     OpenBLAS build complete. (BLAS CBLAS LAPACK)
    
      OS               ... Linux             
      Architecture     ... x86_64               
      BINARY           ... 64bit                 
      C compiler       ... GCC  (command line : gcc)
      Fortran compiler ... GFORTRAN  (command line : gfortran)
      Library Name     ... libopenblas-r0.3.9.a (Single threaded)  
    
    To install the library, you can run "make PREFIX=/path/to/your/installation install".
    
    Removing intermediate container 41f18b3da43e
     ---> c5545163375d
    Step 10/10 : RUN make PREFIX=/usr NO_STATIC=1 install
     ---> Running in 80583523b475
    make -j 8 -f Makefile.install install
    make[1]: Entering directory '/src/OpenBLAS-0.3.9'
    Generating openblas_config.h in /usr/include
    Generating f77blas.h in /usr/include
    Generating cblas.h in /usr/include
    Copying LAPACKE header files to /usr/include
    Copying the shared library to /usr/lib
    Generating openblas.pc in /usr/lib/pkgconfig
    Generating OpenBLASConfig.cmake in /usr/lib/cmake/openblas
    Generating OpenBLASConfigVersion.cmake in /usr/lib/cmake/openblas
    Install OK!
    make[1]: Leaving directory '/src/OpenBLAS-0.3.9'
    ...
    ...
    Removing intermediate container 80583523b475
     ---> 980e4e15139b
    Successfully built 980e4e15139b
    Successfully tagged soulteary/milvus-openblas:0.3.9-intel-20.04
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    如果你的构建环境获取 GitHub Release 中的源码包存在网络问题,可以考虑在构建参数中使用 --build-arg=https_proxy=YOUR_PROXY_ADDR ,强制内容获取走你的指定网络来解决问题。

    同样的,我们可以执行下面的命令,来搞定 Ubuntu 22.04 环境下,OpenBLAS 0.3.20 版本的镜像构建:

    docker build --build-arg=LTS=22.04 --build-arg=OPENBLAS_VERSION=0.3.20 -t soulteary/milvus-openblas:0.3.20-intel-22.04 .
    
    • 1

    同理,我们可以根据切换参数的内容,来完成 Ubuntu 20.04 和 Ubuntu 18.04 系统版本下 OpenBLAS 0.3.9 和 0.3.20 两个版本的镜像构建:

    docker build \
        --build-arg=LTS=20.04 \
        --build-arg=OPENBLAS_VERSION=0.3.9 \
        -t soulteary/milvus-openblas:0.3.9-intel-x86-ubuntu-20.04 .
    docker build \
        --build-arg=LTS=20.04 \
        --build-arg=OPENBLAS_VERSION=0.3.20 \
        -t soulteary/milvus-openblas:0.3.20-intel-x86-ubuntu-20.04 .
    ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    为了节约篇幅,完整内容,我已经上传到了 GitHub,有需要的同学可以自取:soulteary/docker-openblas/blob/main/intel/build.sh

    基于 AMD Zen 架构 CPU 的容器预构建

    和 Intel x86 小节中的最大不同是,在 AMD Zen 架构的 CPU 的容器构建中,由于比较老的版本的 OpenBLAS 在该架构上的兼容性存在问题,即使能构建出来产物,看着一堆堆的测试报错、警告,以及测试安装时的错误日志,也没有人能放心的使用它们,所以我们只构建 OpenBLAS 0.3.20 版本。

    此外,在构建 Intel x86 架构 CPU 的时候,我们的构建参数使用的是 TARGET=CORE2,在构建 AMD Zen 架构镜像的时候,需要替换为 TARGET=ZEN。完整的镜像文件,我上传到了 GitHub:soulteary/docker-openblas/blob/main/amd-zen/Dockerfile,有需要可以自取。

    构建命令,和构建 Intel x86 时类似,也是通过改变参数,来调整构建环境,和使用软件的版本:

    docker build \
        --build-arg=LTS=22.04 \
        --build-arg=OPENBLAS_VERSION=0.3.20 \
        -t soulteary/milvus-openblas:0.3.20-intel-x86-ubuntu-22.04 .
    
    docker build \
        --build-arg=LTS=20.04 \
        --build-arg=OPENBLAS_VERSION=0.3.20 \
        -t soulteary/milvus-openblas:0.3.20-intel-x86-ubuntu-20.04 .
    
    docker build \
        --build-arg=LTS=18.04 \
        --build-arg=OPENBLAS_VERSION=0.3.20 \
        -t soulteary/milvus-openblas:0.3.20-intel-x86-ubuntu-18.04 .
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    命令执行完毕,将会得到类似下面的结果:

    ...
    make[1]: Leaving directory '/src/OpenBLAS-0.3.20/exports'
    
     OpenBLAS build complete. (BLAS CBLAS LAPACK)
    
      OS               ... Linux             
      Architecture     ... x86_64               
      BINARY           ... 64bit                 
      C compiler       ... GCC  (cmd & version : gcc (Ubuntu 11.2.0-19ubuntu1) 11.2.0)
      Fortran compiler ... GFORTRAN  (cmd & version : GNU Fortran (Ubuntu 11.2.0-19ubuntu1) 11.2.0)
      Library Name     ... libopenblas-r0.3.20.a (Single-threading)  
      Supporting multiple x86_64 cpu models with minimum requirement for the common code being ZEN
    
    To install the library, you can run "make PREFIX=/path/to/your/installation install".
    
    Removing intermediate container f276420c3691
     ---> a094af160f34
    Step 10/10 : RUN make PREFIX=/usr NO_STATIC=1 install
     ---> Running in aa4ce3961832
    make -j 16 -f Makefile.install install
    make[1]: Entering directory '/src/OpenBLAS-0.3.20'
    Generating openblas_config.h in /usr/include
    Generating f77blas.h in /usr/include
    Generating cblas.h in /usr/include
    Copying LAPACKE header files to /usr/include
    Copying the shared library to /usr/lib
    Generating openblas.pc in /usr/lib/pkgconfig
    Generating OpenBLASConfig.cmake in /usr/lib/cmake/openblas
    Generating OpenBLASConfigVersion.cmake in /usr/lib/cmake/openblas
    Install OK!
    make[1]: Leaving directory '/src/OpenBLAS-0.3.20'
    ...
    Removing intermediate container aa4ce3961832
     ---> 5aebe4bd2ed3
    Successfully built 5aebe4bd2ed3
    Successfully tagged soulteary/milvus-openblas:0.3.20-amd-zen-ubuntu-22.04
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    最终,将镜像都构建完毕之后,我们能够得到下面的结果:

    soulteary/milvus-openblas     0.3.20-amd-zen-ubuntu-22.04     143MB
    soulteary/milvus-openblas     0.3.20-amd-zen-ubuntu-18.04     266MB
    soulteary/milvus-openblas     0.3.20-amd-zen-ubuntu-20.04     318MB
    
    • 1
    • 2
    • 3

    基于 ARMv64 架构 CPU 的容器预构建

    依旧是先准备 Dockerfile,和 AMD Zen 架构 CPU 遇到的问题类似,0.3.9 版本和一些 Ubuntu 发行版中,我们会在构建过程和结果中遇到一些报错和警告,虽然能够得到构建产物,但是和上面的原因一样,我们需要的是稳定、可靠的产物,所以,可以排除掉 0.3.9 版本的 OpenBLAS 的所有“镜像组合”。

    对于 ARMv64 设备的镜像构建,我们可以使用两种方式。一是使用在以往文章中提到过的 buildx 来进行构建,下面的命令将在构建完毕之后,自动将镜像推送到 DockerHub 中:

    docker buildx build -t group/name:version -f ./Dockerfile.armv8 --push --platform=linux/arm64 .
    
    • 1

    此外,我们还可以选择和上文中构建 Intel / AMD x86 CPU 一样,将构建的事情,放在具有这个硬件架构的设备上完成构建。相比较前者,这样的构建效率有质的不同(快的多的多),恰好这几种 CPU 的设备我手头都有,所以我就选择第二种方案啦。

    不过,和上文中 x86 CPU 的构建配置还是有一些不同,我们需要指定构建参数为 TARGET=ARMV8,完整 Dockerfile,我上传到了 GitHub soulteary/docker-openblas/blob/main/armv8/Dockerfile,有需要可以自取。

    在准备好 Dockerfile 之后,我们使用下面的命令进行 ARMv8 环境下的镜像构建:

    docker build \
        --build-arg=LTS=22.04 \
        --build-arg=OPENBLAS_VERSION=0.3.20 \
        -t soulteary/milvus-openblas:0.3.20-armv8-ubuntu-22.04 .
    
    docker build \
        --build-arg=LTS=20.04 \
        --build-arg=OPENBLAS_VERSION=0.3.20 \
        -t soulteary/milvus-openblas:0.3.20-armv8-ubuntu-20.04 .
    
    docker build \
        --build-arg=LTS=18.04 \
        --build-arg=OPENBLAS_VERSION=0.3.20 \
        -t soulteary/milvus-openblas:0.3.20-armv8-ubuntu-18.04 .
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    相比较 x86 环境下的构建,ARMv8 环境的产物镜像会构建的飞快,并且产物会小巧不少:

    soulteary/milvus-openblas   0.3.20-armv8-ubuntu-22.04     88.8MB
    soulteary/milvus-openblas   0.3.20-armv8-ubuntu-20.04     169MB
    soulteary/milvus-openblas   0.3.20-armv8-ubuntu-18.04     147MB
    
    • 1
    • 2
    • 3

    好啦,到这里如何在容器中构建 OpenBLAS 就分享完毕啦。

    如何使用

    镜像的使用本为两部分,第一部分是获取镜像,你既可以使用我制作好的镜像,也可以进行自行构建。第二部分,则是在容器中使用多阶段构建,完成“软件安装”(跨镜像文件 COPY)。

    如果你不想花费时间重新构建这几类不同硬件环境的镜像,可以使用我提过的镜像文件,经过 DockerHub 的压缩,这些镜像的尺寸得以进一步变得苗条,最小的镜像不过 20MB,最大的也才 47 MB:https://hub.docker.com/repository/docker/soulteary/milvus-openblas/tags

    如果你希望自行构建,根据自己的需求改变构建参数,使用起来心里更踏实,也可以参考我的项目 https://github.com/soulteary/docker-openblas,并结合上文进行构建参数调整,来进行本地构建。

    聊完了镜像的获取,我们来看看镜像在容器中如何使用吧。

    关于预构建镜像的使用,其实非常简单,就如同我们执行 make install 一样,将文件拷贝到正确的目录中,并按照“传统”用软链做好副本的重命名即可,比如这样:

    FROM soulteary/milvus-openblas:0.3.20-intel-x86-ubuntu-20.04 AS OpenBLAS
    
    FROM ubuntu:20.04
    LABEL maintainer=soulteary@gmail.com
    
    COPY --from=OpenBLAS /usr/lib/libopenblas-r0.3.20.so /usr/lib/
    RUN ln -s /usr/lib/libopenblas-r0.3.20.so /usr/lib/libopenblas.so.0 && \
        ln -s /usr/lib/libopenblas.so.0 /usr/lib/libopenblas.so
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在使用过程中,我们只需要保证基础镜像(Ubuntu)版本是对号的,CPU 运行环境是对号的,那么就都能够通过上面这种“跨镜像”复制的方式,来减少 Milvus 或者其他软件构建过程中的时间浪费。

    最后

    既然本文主要聊 OpenBLAS 的容器构建,Milvus 相关的内容,我们还是在之后的文章中,再进行展开吧。

    在接下来的向量数据库相关的内容中,我们将继续聊聊之前立过的各种 Flag。以及不断分享如何把一个原本需要非常长时间构建的软件,不断优化到一个喝杯水就能搞定的程度。

    毕竟使用这类带有“魔法”的软件完成一些好玩的事情之外,让这些“魔法”能够生效的更快、能量更强,也是一件十分有趣的事情。

    –EOF


    本文使用「署名 4.0 国际 (CC BY 4.0)」许可协议,欢迎转载、或重新修改使用,但需要注明来源。 署名 4.0 国际 (CC BY 4.0)

    本文作者: 苏洋

    创建时间: 2022年07月31日
    统计字数: 12186字
    阅读时间: 25分钟阅读
    本文链接: https://soulteary.com/2022/07/31/into-vector-computing-making-openblas-docker-prebuilt-product-images.html

  • 相关阅读:
    Postman内置动态参数和自定义的动态参数以及断言方式
    ClickHouse场景及其原理
    IDEA插件开发(15)---工具窗口
    用核心AI资产打造稀缺电竞体验,顺网灵悉背后有一盘大棋
    Spring MVC中的拦截器
    利用hutool树结构工具-TreeUtil显示多级菜单树状结构
    python的seek()和tell()
    1107 老鼠爱大米分数 20
    Java连接数据库(JDBC非常重要)
    C++11 --- lambda表达式
  • 原文地址:https://blog.csdn.net/soulteary/article/details/126080469