手写vite插件教程示例

目录
  • 前言
  • 1. 什么是 vite 插件
  • 2. 为什么要写 vite 插件
  • 创建  vite 插件通用模板
    • 1. 初始化
    • 2. 配置 eslint 和 prettier(可选)
    • 3. 新增 src/index.ts 入口
    • 4. 创建 examples 目录
    • 5. 配置 examples/vite-vue3 项目
    • 6. 安装 tsup 配置运行命令
    • 7. 开发环境运行
    • 8. 发布
  • vite 的插件钩子 hooks 们
    • 1. vite 独有的钩子
    • 2. vite 与 rollup 的通用钩子之构建阶段
    • 3. vite 与 rollup 的通用钩子之输出阶段
    • 4. 插件钩子函数 hooks 的执行顺序(如下图)
    • 5. 插件的执行顺序
  • 手撸一个 vite 插件
  • 最后

前言

大家好,我是易师傅,在现如今 vite 工具快开始盛行之下,我们是不是可以去做一件有意义的事呢,比如写一个 vite 插件,你觉得怎么样?

刚好我们可以趁 vite 插件 生态还未很成熟阶段,做一个让自己顺心,让领导赏心,让社区开心的插件,与之携手共进。

如果大家对 vite 感兴趣可以去看看专栏: 《Vite 从入门到精通》

通过本文你可以学到

  • 如何创建一个 vite 插件模板
  • vite 插件的 各个钩子作用
  • vite 插件的 钩子执行顺序
  • 如何写一个自己的插件

1. 什么是 vite 插件

vite 其实就是一个由原生 ES Module 驱动的新型 Web 开发前端构建工具。

vite 插件 就可以很好的扩展 vite 自身不能做到的事情,比如 文件图片的压缩、 对 commonjs 的支持、 打包进度条 等等。

2. 为什么要写 vite 插件

相信在座的每位同学,到现在对 webpack 的相关配置以及常用插件都了如指掌了吧;

vite 作为一个新型的前端构建工具,它还很年轻,也有很多扩展性,那么为什么我们不趁现在与它一起携手前进呢?做一些于你于我于大家更有意义的事呢?

要想写一个插件,那必须从创建一个项目开始,下面的 vite 插件通用模板 大家以后写插件可以直接clone使用;

插件通用模板 github:体验入口

插件 github:体验入口

建议包管理器使用优先级:pnpm > yarn > npm > cnpm

长话短说,直接开干 ~

创建  vite 插件通用模板

1. 初始化

1.1 创建一个文件夹并且初始化:初始化按照提示操作即可

mkdir vite-plugin-progress && cd vite-plugin-progress && pnpm init

1.2 安装 typescript

pnpm i typescript @types/node -D

1.3 配置 tsconfig.json

{
  "compilerOptions": {
    "module": "ESNext",
    "target": "esnext",
    "moduleResolution": "node",
    "strict": true,
    "declaration": true,
    "noUnusedLocals": true,
    "esModuleInterop": true,
    "outDir": "dist",
    "lib": ["ESNext"],
    "sourceMap": false,
    "noEmitOnError": true,
    "noImplicitAny": false
  },
  "include": [
    "src/*",
    "*.d.ts"
  ],
  "exclude": [
    "node_modules",
    "examples",
    "dist"
  ]
}

1.4 安装 vite

// 进入 package.json
{
    ...
    "devDependencies": {
        "vite": "*"
    }
    ...
}

2. 配置 eslint 和 prettier(可选)

安装 eslint

pnpm i eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin --save-dev

配置 .eslintrc:配置连接

安装 prettier (可选)

pnpm i prettier eslint-config-prettier eslint-plugin-prettier --save-dev

配置 .prettierrc :配置连接

3. 新增 src/index.ts 入口

import type { PluginOption } from 'vite';
export default function vitePluginTemplate(): PluginOption {
  return {
    // 插件名称
    name: 'vite-plugin-template',
    // pre 会较于 post 先执行
    enforce: 'pre', // post
    // 指明它们仅在 'build' 或 'serve' 模式时调用
    apply: 'build', // apply 亦可以是一个函数
    config(config, { command }) {
      console.log('这里是config钩子');
    },
    configResolved(resolvedConfig) {
      console.log('这里是configResolved钩子');
    },
    configureServer(server) {
      console.log('这里是configureServer钩子');
    },
    transformIndexHtml(html) {
      console.log('这里是transformIndexHtml钩子');
    },
  }
}

其中的 vite 插件函数钩子会在下面详细详解 ~

到这里,那么我们的基本模版就建好了,但是我们现在思考一下,我们应该怎么去运行这个插件呢?

那么我们就需要创建一些 examples 例子来运行这个代码了;

4. 创建 examples 目录

我这里创建了三套项目 demo,大家直接 copy 就行了,这里就不详细介绍了

vite-react

vite-vue2

vite-vue3

如果你的插件需要多跑一些 demo,自行创建项目即可;

那么下面我们就需要配置 examples 下的项目与当前根目录的插件做一个联调了(下面以 examples/vite-vue3 为例)。

5. 配置 examples/vite-vue3 项目

修改 examples/vite-vue3/package.json

{
    ...
    "devDependencies": {
        ...
        "vite": "link:../../node_modules/vite",
        "vite-plugin-template": "link:../../"
    }
}

上面意思就是说:

要把 examples/vite-vue3 项目中的 vite 版本与根目录 vite-plugin-template 的版本一致;

同时要把 examples/vite-vue3 项目中的 vite-plugin-template 指向你当前根目录所开发的插件;

引入插件: examples/vite-vue3/vite.config.ts

import template from 'vite-plugin-template';
export default defineConfig({
    ...
    plugins: [vue(), template()],
    ...
});

安装: cd examples/vite-vue3 && pnpm install

cd examples/vite-vue3 && pnpm install

注意:

examples/vite-vue2 和 examples/vite-react 的配置与这一致

思考:

到这里,我们再思考一下,我们把 examples/vite-vue3 中的项目配置好了,但是我们应该怎么去运行呢?

直接去 examples/vite-vue3 目录下运行 pnpm run build 或者 pnpm run dev ?

这样显然是不能运行成功的,因为我们的根目录下的 src/index.ts 是没法直接运行的,所以我们需要把 .ts 文件转义成 .js 文件;

那么我们怎么处理呢?

那么我们不得不去试着用用一个轻小且无需配置的工具 tsup 了。

6. 安装 tsup 配置运行命令

tsup 是一个轻小且无需配置的,由 esbuild 支持的构建工具;

同时它可以直接把 .ts、.tsx 转成不同格式 esm、cjs、iife 的工具;

安装 tsup

pnpm i tsup -D

在根目录下的 package.json 中配置

{
  ...
  "scripts": {
    "dev": "pnpm run build -- --watch --ignore-watch examples",
    "build": "tsup src/index.ts --dts --format cjs,esm",
    "example:react": "cd examples/vite-react && pnpm run build",
    "example:vue2": "cd examples/vite-vue2 && pnpm run build",
    "example:vue3": "cd examples/vite-vue3 && pnpm run build"
  },
  ...
}

7. 开发环境运行

开发环境运行:实时监听文件修改后重新打包(热更新)

pnpm run dev

运行 examples 中的任意一个项目(以 vite-vue3 为例)

pnpm run example:vue3

注意:

如果你的插件只会在 build 时运行,那就设置

"example:vue3": "cd examples/vite-vue3 && pnpm run build" ;

反之就运行

pnpm run dev

输出:

到这里你就可以 边开发边运行 了,尤雨溪看了都说爽歪歪 ~

8. 发布

安装 bumpp 添加版本控制与 tag

pnpm i bumpp -D

配置 package.json

{
  ...
  "scripts": {
    ...
    "prepublishOnly": "pnpm run build",
    "release": "npx bumpp --push --tag --commit && pnpm publish",
  },
  ...
}

开发完插件后运行发布

# 第一步
pnpm run prepublishOnly
# 第二步
pnpm run release

那么到这里,我们的 vite 插件模板 就已经写好了,大家可以直接克隆 vite-plugin-template 模板 使用;

如果你对 vite 的插件钩子 和 实现一个真正的 vite 插件 感兴趣可以继续往下面看;

vite 的插件钩子 hooks 们

1. vite 独有的钩子

  • enforce :值可以是pre 或 post , pre 会较于 post 先执行;
  • apply :值可以是 build 或 serve 亦可以是一个函数,指明它们仅在 build 或 serve 模式时调用;
  • config(config, env) :可以在 vite 被解析之前修改 vite 的相关配置。钩子接收原始用户配置 config 和一个描述配置环境的变量env;
  • configResolved(resolvedConfig) :在解析 vite 配置后调用。使用这个钩子读取和存储最终解析的配置。当插件需要根据运行的命令做一些不同的事情时,它很有用。
  • configureServer(server) :主要用来配置开发服务器,为 dev-server (connect 应用程序) 添加自定义的中间件;
  • transformIndexHtml(html) :转换 index.html 的专用钩子。钩子接收当前的 HTML 字符串和转换上下文;
  • handleHotUpdate(ctx):执行自定义HMR更新,可以通过ws往客户端发送自定义的事件;

2. vite 与 rollup 的通用钩子之构建阶段

  • options(options) :在服务器启动时被调用:获取、操纵Rollup选项,严格意义上来讲,它执行于属于构建阶段之前;
  • buildStart(options):在每次开始构建时调用;
  • resolveId(source, importer, options):在每个传入模块请求时被调用,创建自定义确认函数,可以用来定位第三方依赖;
  • load(id):在每个传入模块请求时被调用,可以自定义加载器,可用来返回自定义的内容;
  • transform(code, id):在每个传入模块请求时被调用,主要是用来转换单个模块;
  • buildEnd():在构建阶段结束后被调用,此处构建结束只是代表所有模块转义完成;

3. vite 与 rollup 的通用钩子之输出阶段

  • outputOptions(options):接受输出参数;
  • renderStart(outputOptions, inputOptions):每次 bundle.generate 和 bundle.write 调用时都会被触发;
  • augmentChunkHash(chunkInfo):用来给 chunk 增加 hash;
  • renderChunk(code, chunk, options):转译单个的chunk时触发。rollup 输出每一个chunk文件的时候都会调用;
  • generateBundle(options, bundle, isWrite):在调用 bundle.write 之前立即触发这个 hook;
  • writeBundle(options, bundle):在调用 bundle.write后,所有的chunk都写入文件后,最后会调用一次 writeBundle;
  • closeBundle():在服务器关闭时被调用

4. 插件钩子函数 hooks 的执行顺序(如下图)

5. 插件的执行顺序

  • 别名处理Alias
  • 用户插件设置enforce: 'pre'
  • vite 核心插件
  • 用户插件未设置enforce
  • vite 构建插件
  • 用户插件设置enforce: 'post'
  • vite 构建后置插件(minify, manifest, reporting)

手撸一个 vite 插件

下面以 vite 打包进度条 插件为例;

插件地址:github

该插件已被 vite 官方收集至官方文档:链接地址

因为文章的重点不在于这个插件的详细实现过程,所以本文只会贴上源代码供大家参考,详细介绍会在下一篇文章中讲解,请大家拭目以待吧!

inde.ts

import type { PluginOption } from 'vite';
import colors from 'picocolors';
import progress from 'progress';
import rd from 'rd';
import { isExists, getCacheData, setCacheData } from './cache';
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
type Merge<M, N> = Omit<M, Extract<keyof M, keyof N>> & N;
type PluginOptions = Merge<
    ProgressBar.ProgressBarOptions,
    {
        /**
         * total number of ticks to complete
         * @default 100
         */
        total?: number;
        /**
         * The format of the progress bar
         */
        format?: string;
    }
>;
export default function viteProgressBar(options?: PluginOptions): PluginOption {
    const { cacheTransformCount, cacheChunkCount } = getCacheData()
    let bar: progress;
    const stream = options?.stream || process.stderr;
    let outDir: string;
    let transformCount = 0
    let chunkCount = 0
    let transformed = 0
    let fileCount = 0
    let lastPercent = 0
    let percent = 0
    return {
        name: 'vite-plugin-progress',
        enforce: 'pre',
        apply: 'build',
        config(config, { command }) {
            if (command === 'build') {
                config.logLevel = 'silent';
                outDir = config.build?.outDir || 'dist';
                options = {
                    width: 40,
                    complete: '\u2588',
                    incomplete: '\u2591',
                    ...options
                };
                options.total = options?.total || 100;
                const transforming = isExists ? `${colors.magenta('Transforms:')} :transformCur/:transformTotal | ` : ''
                const chunks = isExists ? `${colors.magenta('Chunks:')} :chunkCur/:chunkTotal | ` : ''
                const barText = `${colors.cyan(`[:bar]`)}`
                const barFormat =
                    options.format ||
                    `${colors.green('Bouilding')} ${barText} :percent | ${transforming}${chunks}Time: :elapseds`
                delete options.format;
                bar = new progress(barFormat, options as ProgressBar.ProgressBarOptions);
                // not cache: Loop files in src directory
                if (!isExists) {
                    const readDir = rd.readSync('src');
                    const reg = /\.(vue|ts|js|jsx|tsx|css|scss||sass|styl|less)$/gi;
                    readDir.forEach((item) => reg.test(item) && fileCount++);
                }
            }
        },
        transform(code, id) {
            transformCount++
            // not cache
            if(!isExists) {
                const reg = /node_modules/gi;
                if (!reg.test(id) && percent < 0.25) {
                    transformed++
                    percent = +(transformed / (fileCount * 2)).toFixed(2)
                    percent < 0.8 && (lastPercent = percent)
                  }
                if (percent >= 0.25 && lastPercent <= 0.65) {
                    lastPercent = +(lastPercent + 0.001).toFixed(4)
                }
            }
            // go cache
            if (isExists) runCachedData()
            bar.update(lastPercent, {
                transformTotal: cacheTransformCount,
                transformCur: transformCount,
                chunkTotal: cacheChunkCount,
                chunkCur: 0,
            })
            return {
                code,
                map: null
            };
        },
        renderChunk() {
            chunkCount++
            if (lastPercent <= 0.95)
                isExists ? runCachedData() : (lastPercent = +(lastPercent + 0.005).toFixed(4))
            bar.update(lastPercent, {
                transformTotal: cacheTransformCount,
                transformCur: transformCount,
                chunkTotal: cacheChunkCount,
                chunkCur: chunkCount,
            })
            return null
        },
        closeBundle() {
            // close progress
            bar.update(1)
            bar.terminate()
            // set cache data
            setCacheData({
                cacheTransformCount: transformCount,
                cacheChunkCount: chunkCount,
            })
            // out successful message
            stream.write(
                `${colors.cyan(colors.bold(`Build successful. Please see ${outDir} directory`))}`
            );
            stream.write('\n');
            stream.write('\n');
        }
    };
    /**
     * run cache data of progress
     */
    function runCachedData() {
        if (transformCount === 1) {
            stream.write('\n');
            bar.tick({
                transformTotal: cacheTransformCount,
                transformCur: transformCount,
                chunkTotal: cacheChunkCount,
                chunkCur: 0,
            })
        }
        transformed++
        percent = lastPercent = +(transformed / (cacheTransformCount + cacheChunkCount)).toFixed(2)
    }
}

cache.ts

import fs from 'fs';
import path from 'path';
const dirPath = path.join(process.cwd(), 'node_modules', '.progress');
const filePath = path.join(dirPath, 'index.json');
export interface ICacheData {
    /**
     * Transform all count
     */
    cacheTransformCount: number;
    /**
     * chunk all count
     */
    cacheChunkCount: number
}
/**
 * It has been cached
 * @return boolean
 */
export const isExists = fs.existsSync(filePath) || false;
/**
 * Get cached data
 * @returns ICacheData
 */
export const getCacheData = (): ICacheData =&gt; {
    if (!isExists) return {
        cacheTransformCount: 0,
        cacheChunkCount: 0
    };
    return JSON.parse(fs.readFileSync(filePath, 'utf8'));
};
/**
 * Set the data to be cached
 * @returns
 */
export const setCacheData = (data: ICacheData) =&gt; {
    !isExists &amp;&amp; fs.mkdirSync(dirPath);
    fs.writeFileSync(filePath, JSON.stringify(data));
};

最后

该系列会是一个持续更新系列,关于整个《Vite 从入门到精通》专栏,我主要会从如下图几个方面讲解,请大家拭目以待吧!!!

以上就是手写vite插件教程示例的详细内容,更多关于vite插件教程的资料请关注我们其它相关文章!

(0)

相关推荐

  • Vite vue3多页面入口打包以及部署踩坑实战

    目录 为什么需要多入口? 一.改造项目 二.vite.config.ts配置 三.部署 总结 为什么需要多入口? 公司原生的移动端上需要用webview引入一些性能要求不高的H5页面,初步考虑后选择用vue试个水,前期页面跳转选择使用vue-router,测试过程中在安卓高版本下右滑返回效果尚可,ios端初步尝试使用的最左侧touch事件移动距离检测以及router判断index添加过场动画,但是整体的效果依然达不到下图的效果. 原先项目中是使用多个html页面以及原生自带的协议去打开html,

  • vue3+vite使用jsx和tsx详情

    目录 安装@vitejs/plugin-vue-jsx 配置vite.config.js 使用实战 第一种写法使用this 第二种写法 第三种写法 安装@vitejs/plugin-vue-jsx yarn add -D @vitejs/plugin-vue-jsx npm i -D @vitejs/plugin-vue-jsx 配置vite.config.js ... import vueJsx from '@vitejs/plugin-vue-jsx'; export default def

  • Vue3中级指南之如何在vite中使用svg图标详解

    目录 前言 vite-plugin-svg-icons 安装 使用 如何在组件中使用 创建SvgIcon组件 icons目录结构 全局注册组件 页面使用 获取所有 SymbolId 总结 前言 svg图片在项目中使用的非常广泛,今天记录一下我是如何在vue3 + vite 中使用svg图标. vite-plugin-svg-icons 预加载 在项目运行时就生成所有图标,只需操作一次 dom 高性能 内置缓存,仅当文件被修改时才会重新生成 安装 node version:  >=12.0.0 v

  • vite多页面配置项目实战

    目录 目录结构 多页面使用时,vite配置项中注意点 vite.config.js 配置,仅供参考 访问 总结 最近有多页面项目需要重构,就想试试使用vite,但是网上很多方法不太全面踩了不少的坑,网上的多页面配置方案也不少,我只给出了我成功配置并在使用的方案 目录结构 { dist: // 存放打包后的文件, node_modules: , src: { assets: // 一些静态文件, components: // 公用组件, index: { // 页面1 index.html, ma

  • vite2打包的时候vendor-xxx.js文件过大的解决方法

    vite2是一个非常好用的工具,只是随着代码的增多,打包的时候 vendor-xxxxxx.js 文件也越来越大,这就郁闷了. 打包时遇到警告 输出文件名字/static/vendor.9b5698e4.js 806.03kb / brotli: skipped (large chunk) Some chunks are larger than 500kb after minification. Consider: Using dynamic import() to code-split the

  • 如何用Vite构建工具快速创建Vue项目

    目录 和Webpack相比,Vite具有以下特点 Vite构建Vue项目 构建过程可能会发生的一些问题 总结 和Webpack相比,Vite具有以下特点 1.快速的冷启动,不需要等待打包 2.即时的热模块更新,真正的按需编译,不用等待整个项目编译完成 Vite构建Vue项目 前提:安装Node.js和Vite 第一步通过npm创建Vite项目 npm init vite-app 项目名称 # 例如 npm init vite-app HelloVue 第二步当项目创建成功后,cd到项目目录 cd

  • vite插件打包更顺畅使用技巧示例

    目录 前言 前言 介绍 用法 使用(带参数): 给自定义进度条加点颜色: 实现思路 第一次打包(模拟模块总数) 与进度条配合 添加缓存 使用缓存 实现架构图 最后 前言 前言 在上一篇给大家带来了<如何入门去写一个 vite 插件>,能看的出来同学们也甚是喜欢,如果大家对 vite 感兴趣,可以关注我的专栏<vite 从入门到精通>: 因为公司目前大部分项目都已转为 vite,为了给社区添加一份贡献,故开发了一个已经应用到项目中的vite 前端打包进度条 的插件 vite-plug

  • 手写vite插件教程示例

    目录 前言 1. 什么是 vite 插件 2. 为什么要写 vite 插件 创建  vite 插件通用模板 1. 初始化 2. 配置 eslint 和 prettier(可选) 3. 新增 src/index.ts 入口 4. 创建 examples 目录 5. 配置 examples/vite-vue3 项目 6. 安装 tsup 配置运行命令 7. 开发环境运行 8. 发布 vite 的插件钩子 hooks 们 1. vite 独有的钩子 2. vite 与 rollup 的通用钩子之构建阶

  • pytorch教程实现mnist手写数字识别代码示例

    目录 1.构建网络 2.编写训练代码 3.编写测试代码 4.指导程序train和test 5.完整代码 1.构建网络 nn.Moudle是pytorch官方指定的编写Net模块,在init函数中添加需要使用的层,在foeword中定义网络流向. 下面详细解释各层: conv1层:输入channel = 1 ,输出chanael = 10,滤波器5*5 maxpooling = 2*2 conv2层:输入channel = 10 ,输出chanael = 20,滤波器5*5, dropout ma

  • 超详细PyTorch实现手写数字识别器的示例代码

    前言 深度学习中有很多玩具数据,mnist就是其中一个,一个人能否入门深度学习往往就是以能否玩转mnist数据来判断的,在前面很多基础介绍后我们就可以来实现一个简单的手写数字识别的网络了 数据的处理 我们使用pytorch自带的包进行数据的预处理 import torch import torchvision import torchvision.transforms as transforms import numpy as np import matplotlib.pyplot as plt

  • PyTorch实现手写数字识别的示例代码

    目录 加载手写数字的数据 数据加载器(分批加载) 建立模型 模型训练 测试集抽取数据,查看预测结果 计算模型精度 自己手写数字进行预测 加载手写数字的数据 组成训练集和测试集,这里已经下载好了,所以download为False import torchvision # 是否支持gpu运算 # device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # print(device) # print(torch.cud

  • React手写一个手风琴组件示例

    目录 知识点 结构分析 AccordionItem子组件 Accordion容器组件 知识点 emotion语法 react语法 css语法 typescript类型语法 结构分析 根据上图,我们来分析一下,一个手风琴组件应该包含一个手风琴容器组件和多个手风琴子元素组件.因此,假设我们实现好了所有的逻辑,并写出使用demo,那么代码应该如下: <Accordion defaultIndex="1" onItemClick={console.log}> <Accordi

  • 利用Java手写阻塞队列的示例代码

    目录 前言 需求分析 阻塞队列实现原理 线程阻塞和唤醒 数组循环使用 代码实现 成员变量定义 构造函数 put函数 offer函数 add函数 take函数 重写toString函数 完整代码 总结 前言 在我们平时编程的时候一个很重要的工具就是容器,在本篇文章当中主要给大家介绍阻塞队列的原理,并且在了解原理之后自己动手实现一个低配版的阻塞队列. 需求分析 在前面的两篇文章ArrayDeque(JDK双端队列)源码深度剖析和深入剖析(JDK)ArrayQueue源码当中我们仔细介绍了队列的原理,

  • 手写Java LockSupport的示例代码

    目录 前言 LockSupport实现原理 自己动手实现自己的LockSupport 实现原理 自己实现LockSupport协议规定 工具 具体实现 完整代码 JVM实现一瞥 总结 前言 在JDK当中给我们提供的各种并发工具当中,比如ReentrantLock等等工具的内部实现,经常会使用到一个工具,这个工具就是LockSupport.LockSupport给我们提供了一个非常强大的功能,它是线程阻塞最基本的元语,他可以将一个线程阻塞也可以将一个线程唤醒,因此经常在并发的场景下进行使用. Lo

  • Java实现手写自旋锁的示例代码

    目录 前言 自旋锁 原子性 自己动手写自旋锁 自己动手写可重入自旋锁 总结 前言 我们在写并发程序的时候,一个非常常见的需求就是保证在某一个时刻只有一个线程执行某段代码,像这种代码叫做临界区,而通常保证一个时刻只有一个线程执行临界区的代码的方法就是锁.在本篇文章当中我们将会仔细分析和学习自旋锁,所谓自旋锁就是通过while循环实现的,让拿到锁的线程进入临界区执行代码,让没有拿到锁的线程一直进行while死循环,这其实就是线程自己“旋”在while循环了,因而这种锁就叫做自旋锁. 自旋锁 原子性

  • Java实现手写线程池的示例代码

    目录 前言 线程池给我们提供的功能 工具介绍 Worker设计 线程池设计 总结 前言 在我们的日常的编程当中,并发是始终离不开的主题,而在并发多线程当中,线程池又是一个不可规避的问题.多线程可以提高我们并发程序的效率,可以让我们不去频繁的申请和释放线程,这是一个很大的花销,而在线程池当中就不需要去频繁的申请线程,他的主要原理是申请完线程之后并不中断,而是不断的去队列当中领取任务,然后执行,反复这样的操作.在本篇文章当中我们主要是介绍线程池的原理,因此我们会自己写一个非常非常简单的线程池,主要帮

  • C语言手写集合List的示例代码

    目录 前沿 定义结构 创建List 扩容 创建数据节点 给集合添加值 删除集合内指定的值 删除集合内指定下标的值 打印集合 迭代器 查询指定元素的下标(第一个) 末尾查询指定元素下标(第一个) 判断数组是否有序 二分查询 修改集合指定元素的值 快速排序 集合去重 集合复制 集合合并 集合差集 集合补集 集合并集 集合交集 销毁集合 前沿 数组长度是固定的,那么在很多时候我们并不知道到底有多少数据需要存储,这时候我么就需要一个可变长度的数组来进行存储,在C语言中需要我们自己进行定义,我们称为集合

随机推荐