【翻译】 zswap 压缩交换缓存

2023-11-20

您知道吗......?

LWN.net 是一份由订阅者支持的出版物;我们依靠订阅者来维持整个运作。 请通过订阅来帮助我们,让 LWN 继续在网络上运行。

2013年2月12日

本文由 Seth Jennings 投稿

交换是性能的最大威胁之一。即使在快速固态硬盘上,RAM 和交换之间的延迟差距也可能达到四个数量级。 吞吐量差距为两个数量级。 除了速度上的差距,交换区所在的存储也越来越多地共享和虚拟化,这可能会导致额外的 I/O 延迟和不确定的工作负载性能。 zswap 子系统的存在就是为了通过减少 I/O 活动来减轻交换带来的这些不良影响。

Zswap 是一种轻量级的交换页写后压缩缓存。 它接收正在被交换的页面,并尝试将其压缩到基于 RAM 的动态分配内存池中。 如果这一过程成功,向交换设备的回写就会推迟,在很多情况下甚至可以完全避免。 这就大大减少了 I/O,并提高了交换系统的性能。

Zswap 基础知识

Zswap 在交换回写过程中拦截页面,并使用前置交换 API 对其进行缓存。 内核自 3.5 版起就加入了前置交换功能,LWN也曾对其进行过报道。 它允许后端驱动程序(如 zswap)拦截交换页面回写和被交换页面的页面故障。Zswap 还利用 "zsmalloc "分配器(下文将讨论)来进行压缩页面存储。

Zswap 在结构和操作上力求简单,主要有两种数据结构。 第一个是zswap_entry结构,它包含了存储在 zswap 中的单个压缩页面的信息:

    struct zswap_entry { struct rb_node rbnode; int refcount; pgoff_t offset; unsigned long handle; /* zsmalloc allocation */ unsigned int length; /* ...*/ };

第二个是zswap_tree结构,它包含一棵由偏移值索引的 zswap 条目组成的红黑树:

    struct zswap_tree { struct rb_root rbroot; struct list_head lru; spinlock_t lock; struct zs_pool *pool; };

在最高层,有一个以交换设备编号为索引的zswap_tree结构数组。

每个zswap_tree有一个锁,用于在查找和修改时保护树结构。 上层交换代码提供了某些保护措施,从而简化了 zswap 的实现,无需对同一交换条目进行并发存储、加载和失效操作。 虽然这种单锁设计看似可能会引起争用,但实际执行情况表明,交换路径的瓶颈主要来自更高层次的其他锁,如anon_vmamutex 或swap_lock。 相比之下,zswap_tree锁的竞争程度很低。 下一节将介绍的回写支持也促成了这种单锁设计。

在页面压缩方面,zswap 使用内核加密 API 提供的压缩器模块。 这允许用户在启动时动态选择压缩器,并方便访问硬件压缩加速器或其他未来的压缩引擎。

当一个页面被回收系统选中进行交换,并且 frontswap 在swap_writepage()中截获该页面时,zswap 存储操作就会发生。 操作开始时,会将页面压缩到每个 CPU 的临时缓冲区中。 之所以需要将页面压缩到临时缓冲区,是因为在实际压缩之前,无法知道压缩后的页面大小,也就无法知道保存页面所需的永久分配大小。 一旦知道压缩后的大小,就会分配一个对象,并将临时缓冲区复制到该对象中。 最后,一个zswap_entry结构会被分配、填充并插入该交换设备的树中。

如果存储因故失败,最可能的原因是对象分配失败,zswap 会返回一个错误,该错误会通过frontswap 上传到swap_writepage()。然后,页面会像往常一样被交换到交换设备上。

当程序页面在包含交换条目的页表项(PTE)上发生错误,并被swap_readpage() 中的 frontswap 拦截时,就会发生加载操作。 交换条目包含在相应的树中查找 zswap 条目所需的设备和偏移量信息,一旦找到该条目,数据就会被直接解压缩到由页面故障代码分配的页面中。 在加载过程中,条目不会从数据树中移除;在条目失效之前,它一直保持最新状态。

当特定交换偏移的引用计数在swap_entry_free()中变为零时,就会发生无效操作。 在这种情况下,zswap 条目会从相应的树中移除,并且该条目及其引用的 zsmalloc 分配会被释放。

为了方便抢占,中断永远不会被禁用。 只有在访问每 CPU 临时缓冲页的压缩过程中,以及访问映射的 zsmalloc 分配的解压缩过程中,才会禁用抢占。

Zswap 回写

为了以最佳方式作为缓存运行,zswap 应保存最近使用的页面。 遗憾的是,使用前置交换时,确实有可能出现最近最少使用(LRU)的反向情况,即缓存中充满了较旧的页面,而较新的页面则被强制写入速度较慢的交换设备。 为了解决这个问题,zswap 在设计时考虑到了 "恢复 "回写。

作为背景,交换页面的过程遵循以下步骤:

  1. 首先,选择一个匿名内存页进行交换,并在交换设备中分配一个插槽。

  2. 然后,从使用该页的所有进程中取消该页的映射。 在引用该页面的 PTE 中填入交换条目,其中包括交换类型和可以找到该页面的偏移量。

  3. 最后,页面会被安排写回交换设备。

如果swap_writepage()中的frontswap_store()操作成功,则不执行回写步骤。 不过,交换设备中的插槽已分配完毕,并仍为该页面保留,即使该页面只存在于 frontswap 后端。 zswap 中的恢复回写会强制页面从压缩缓存中移出,进入交换设备中先前预留的交换槽。 目前,该策略是基本的,会在两种情况下强制将页面从缓存中移出:(1) 当缓存已达到根据max_pool_percentsysfs 可调变量设定的最大大小时,或 (2) 当 zswap 无法为压缩池分配新空间时。

在恢复写回过程中,zswap 会解压缩页面,将其添加回交换缓存,并安排写回之前预留的交换槽。 通过在调用frontswap _store()后将swap_writepage()分成两个函数,zswap 可以从 frontswap 中初始回写终止的位置恢复回写。 新函数名为 __swap_writepage()

有了回写,释放 zswap 条目就变得更加复杂。 如果没有回写,只有在无效操作(zswap_frontswap_invalidate page())时才会释放页面。 使用回写后,也可以在zswap_writeback_pages() 中释放页面。 这些失效和回写函数可以针对同一个 zswap 条目同时运行。 为了保证条目在被其他线程访问时不会被释放,zswap_entry 结构中使用了一个引用计数字段(称为refcount)。

Zsmalloc 的基本原理

说到zswap,就不能不提到zsmalloc,它是zswap用于压缩页面存储的分配器,目前位于Linux暂存树中。

Zsmalloc 是 zswap 使用的一种基于板块的分配器;与内核板块分配器相比,它能在内存受限的环境中为大型对象提供更可靠的分配。 LWN 上已经讨论过 Zsmalloc,因此本节将重点讨论在内核板块分配器存在的情况下使用 zsmalloc 的必要性。

zswap 存储的对象是压缩页面。 默认的压缩器是 lzo1x-1,它以速度著称,但压缩率并不高。 因此,zswap 对象经常会比典型的板块对象大(>1/8PAGE_SIZE)。 在内存压力下,这对内核板块分配器来说是个问题。

内核板块分配器需要高阶页面分配来支持大对象的板块。 例如,在一个页面大小为 4K 的系统上,kmalloc-512缓存的板块需要两个连续页面的支持,而kmalloc-2048每个板块需要八个连续页面。 当系统面临内存压力时,这些高阶页面分配很可能会失败。

Zsmalloc 解决这个问题的方法是,允许支持板块的页面(或用 zsmalloc 术语来说的 "大小类")是非连续的,而且在数量上是可变的。它们在数量上是可变的,因为 zsmalloc 允许一个板块由少于目标数量的后备页组成。 使用struct page的字段将一组非连续页面拼接在一起,以创建一个 "zspage"。 这样,zsmalloc 就可以在不需要高阶页面分配的情况下,为高达PAGE_SIZE 的大型对象分配提供服务。

此外,内核板块分配器不允许大小小于一个页面的对象跨越页面边界。 这意味着,如果一个对象的大小是PAGE_SIZE/2 + 1字节,那么它实际上使用了整个页面,造成了 ~50% 的浪费。 因此,在PAGE_SIZE/2PAGE_SIZE 之间没有kmalloc()缓存大小。 不过,Zswap 经常需要在这个范围内进行分配。 使用内核板块分配器会导致通过压缩节省的内存在碎片化中丢失。

为了满足这些较大的分配需求,同时又不浪费整个页面,zsmalloc 允许对象跨越页面边界,但代价是在访问它们之前必须映射分配。 之所以需要这种映射,是因为对象可能包含在两个不连续的页面中。 例如,在一个对象大小为 PAGE_SIZE 2/3 的 zsmalloc 大小类中,可以在一个有两个非连续后备页的 zspage 中存储三个对象,而不会造成浪费。 存储在 zspage 中三个对象中第二个位置的对象将被分割到两个不同的页面中。

Zsmalloc 非常适合 zswap。 我们使用内核板块分配器对 Zswap 进行了评估,这些问题确实对frontswap_store()的成功率产生了重大影响。 这是由于kmalloc()分配失败,以及需要拒绝压缩到大于PAGE_SIZE/2 大小的页面。

性能

为了进行性能比较,我们在内存容量恒定且受限的情况下,通过增加每次运行的线程数进行了内核构建。 结果表明,与普通交换相比,zswap 的运行时间减少了 53%,I/O 减少了 76%。 测试系统配置如下

  • 运行 v3.7-rc7 的 Gentoo
  • 四核 i5-2500 @ 3.3GHz
  • 512MB DDR3 1600MHz
  • (启动时受 mem=512m 限制)
  • 文件系统和交换在 80GB HDD 上(使用 hdparm -t 时速度约为 58MB/s)。

下表总结了测试运行情况。

基准 zswap 变化
N pswpin pswpout majflt 输入/输出总和 pswpin pswpout I/O 和 I/O 总和 %I/O MB
8 1 335 291 627 0 0 249 249 -60% 1
12 3688 14315 5290 23293 123 860 5954 6937 -70% 64
16 12711 46179 16803 75693 2936 7390 46092 56418 -25% 75
20 42178 133781 49898 225857 9460 28382 92951 130793 -42% 371
24 96079 357280 105242 558601 7719 18484 109309 135512 -76% 1653

N "列表示每次运行时内核构建(make -jN)的最大并发线程数。 接下来的四列是不使用 zswap 的基准运行的统计信息,然后是使用 zswap 运行的统计信息。 每次运行的 I/O 总和列是 pswpin(换入页面)、pswpout(换出页面)和 majflt(主要页面故障)的总和。 基线运行和 zswap 运行之间的差异既以 I/O 减少百分比的相对形式显示,也以与交换活动相关的 I/O 减少 X 兆字节的绝对形式显示。

压缩交换缓存降低了页面回收过程的效率。 对于任何存储操作,缓存都可能分配一些页面来存储压缩页面。 这就降低了整体页面回收效率。 效率的降低会给页面缓存带来额外的收缩压力,导致必须从磁盘重新读取页面的重大页面故障增加。 为了全面了解 I/O 的影响,必须在 I/O 总量中考虑主要页面故障。

下表显示了内核构建的总运行时间:

运行时间(秒)
N 基数 zswap %change
8 107 107 0%
12 128 110 -14%
16 191 179 -6%
20 371 240 -35%
24 570 267 -53%

在比较相同线程数的运行时,交换活动对运行时间的影响有所降低。 在比较基准线和 zswap 时,对于限制越来越多的运行,性能下降率有所降低。

构建过程中 CPU 平均利用率的测量结果如下

CPU 利用率百分比(4 个 CPU,满分 400)
N 基准 zswap %变化
8 317 319 1%
12 267 311 16%
16 179 191 7%
20 94 143 52%
24 60 128 113%

CPU 利用率表显示,使用 zswap 后,内核构建能更有效地利用 CPU,这与运行时的结果相符。

其他性能测试使用 SPECjbb 进行。 有关在 x86 和 Power7+(使用或不使用硬件压缩加速)上使用 zswap 所能实现的性能提升和 I/O 减少的指标,可在本页找到。

结论

Zswap 是一种压缩交换缓存,能够在压缩池达到大小限制或无法从好友分配器获取额外页面时,以 LRU 为基础将页面从压缩缓存中驱逐到后备交换设备。 这种权衡可以显著提高性能,因为读取和写入压缩缓存的速度几乎总是快于从交换设备读取数据的速度,因为从交换设备读取数据会产生异步块 I/O 读取的延迟。

本文索引条目
内核 内存管理/交换
内核 超越内存
内核 内存交换
特邀文章 詹宁斯, 塞思


(登录发表评论)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【翻译】 zswap 压缩交换缓存 的相关文章

  • 【翻译】疫苗正在拯救世界!但内容交付网络首先做到了吗?

    2020年1月 一种激进的公共卫生干预措施被介绍给世界 禁闭 在中国推出它之前 它从未在好莱坞以外的任何地方大规模使用过 没有人相信现实生活中的民众会接受连续几个月被关在家里的情况 即使他们的生命取决于此 与所有的预期相反 禁闭正在控制一种
  • 【翻译】我们建立了一个.NET操作员SDK(所以您不必这样做)。

    我们用C 语言构建了一个 NET操作者SDK 因此您可以用C 或任何 NET语言构建自己的Kubernetes操作者 当然也 有Go Operator SDK 还有我们的Java Operator SDK 那么为什么不为 NET社区提供一些
  • 跟我一起学Multiple View Geometry多视图几何(1)

    本系列博客持续更新 与大家交流学习用 若读者发现有错误或者疑问请留言 前言 前几天博主买了本Multiple View Geometry第二版 一直在看这本书 不得不说之前网上查到的好多理论都是出自这本书 所以为了方便自己学习的更加深刻和与
  • 【翻译】是时候与科技建立更持久的关系了吗?

    当轨道交通时间到来时 你可以进行轨道交通 但不是之前 罗伯特 A 海因莱因 在他的SF小说 通往夏天的门 中 海因莱因认为 对于特定形式的技术变革 时间必须是正确的 在必要的技术和文化基础到位之前 它不会发生 问题是 我们是否已经达到了最终
  • 详解卡尔曼滤波原理

    详解卡尔曼滤波原理 在网上看了不少与卡尔曼滤波相关的博客 论文 要么是只谈理论 缺乏感性 或者有感性认识 缺乏理论推导 能兼顾二者的少之又少 直到我看到了国外的一篇博文 真的惊艳到我了 不得不佩服作者这种细致入微的精神 翻译过来跟大家分享一
  • 冰羚中间件 RouDi usage-guide.md翻译

    内容 内容 配置RouDi Configuring RouDi RouDi可以支持读取从一个配置文件中读取mempool config 如果需要支持这个特性 CMake的编译选项中需要使用 DTOML CONFIG on mempool c
  • 【翻译】RFP有什么问题?

    科技行业充斥着首字母缩略词和缩写 有时会引发强烈的反应 RfP这些字母总是让我在黯然神伤和极度沮丧之间摇摆不定 为什么呢 因为征求建议书的过程突出了我们采购和交付软件和基础设施的方式是如何被打破的 从表面上看 传统的提案申请程序是非常合理的
  • 各国语言对应翻译表

    为了工作方便 自己做了一个地区语言的英文翻译 让自己可以更快的找到自己需要的地方 同时 分享给大家 谢谢 中文 各国语言 翻译 序号 中文 翻译 1 阿尔巴尼亚语 2 阿拉伯语 3 阿姆哈拉语 4 阿塞拜疆语 Az rbaycan 5 爱尔
  • 【翻译】 Linux 与无人机的未来

    请考虑订阅 LWN订阅是 LWN net 的生命线 如果您喜欢这些内容并希望看到更多 您的订阅将有助于确保 LWN 继续蓬勃发展 请访问此页面加入我们 让 LWN 继续在网络上传播 作者 Nathan Willis 2015 年 10 月
  • node调用谷歌翻译Api,实现自动国际化

    原因 项目国际化过程繁琐 每次都需要人工去google翻译 导致工作效率不高 需求 1 减少人工的重复劳动 提高工作效率 2 使用脚本调用谷歌翻译接口自动化翻译 3 free 作为程序员肯定接受不了付费服务 找方法解决限制 前期准备 1 谷
  • 【翻译】 2.6 中的 4K 堆栈 [发布于 2004 年 5 月 12 日,作者:corbet

    传统上 Linux 内核在大多数架构上都使用 8KB 内核堆栈 该堆栈必须满足系统调用可能产生的任何调用序列 以及可能同时调用的任何 硬或软 中断处理程序的需要 实际上 在稳定的内核中 堆栈溢出的情况几乎闻所未闻 内核开发人员早已学会避免使
  • 【翻译】BItcoin数据结构——UTXO definition-Investopedia

    原文 https www investopedia com terms u utxo asp UTXO意味着什么 UTXO代表比特币交易的未花费的输出 每个比特币交易都以用于平衡分类账的硬币开始 UTXO会不断处理 并负责开始和结束每笔交易
  • JDBC规范——(8)异常

    当访问一个数据源时发生错误或者警告 JDBC 用 SQLException 这个类及其子类来表示并提供相关的异常信息 8 1 SQLException SQLException 由一下几部分组成 1 描述错误的文本信息 可以通过 SQLEx
  • gitlab CI/CD :创建一个复杂的pipeline流水线

    教程内容原文地址 Tutorial Create a complex pipeline 当前教程版本 16 1 文章目录 先决条件 创建一个项目来保存 Docusaurus 文件 创建初始CI CD的配置文件 添加一个job来构建站点 添加
  • 【翻译】白人男性在改善性别多样性方面的作用是什么?

    我们都知道 或者说现在应该知道 多元化的团队和组织更成功 更有创造力 有更好的留任率 并能带来更健康的工作场所文化 强调这些观点的数据是很多的 然而 技术团队在这方面往往是落后的 艾米丽 张在她的书 Brotopia 中认为 在一个如此有力
  • 【翻译】知识的诅咒

    巧合的是 本周我和五组不同的人进行了同样的对话 我想我应该把我的想法写下来 并把它们写在博客上 因为这一连串的想法似乎引起了很多人的共鸣 这场对话从一个偏见开始 和我一起工作的许多人是工程师 他们后来可能已经成为高级领导或高管 但他们曾经是
  • 推荐这款神器!每年都有数以百万的大学生想用它!闲鱼都卖两百!

    文末有下载链接 如同明日将死那样生活 如同永远不死那样求知 甘地 image 这是一个能把破解者气死的软件 辛辛苦苦破解的软件 却被别人拿去收费标价200元 真买了 吃亏的是你 在我这 不用钱 说到论文翻译 真的是让人抓狂 每年百万的大学生
  • 【翻译】对计算机未来的10个预测或;我们的首席科学家的无稽之谈

    TLDR WASM将无处不在 编译目标 部署目标 物联网 插件生态系统 这已经在发生了 1 5年 Rust将继续流行 根据RedMonk的指数 在未来几年将超过Go 2 4年 将出现一个严重的Kubernetes的对手 如果它使用WASM并
  • Qt多国语言动态切换(含源代码)

    Qt中文国际化 含高阶做法 作者 melon 日期 2019 7 15 1 国际化需要用到的工具 lrelease exe lupdate exe linguist exe 非必须 这些工具在Qt5 12 2的bin文件夹都可以找到 lup
  • 【翻译】 DMA和get_user_pages()

    LWN net需要你 没有订阅者 LWN将根本不存在 请考虑注册订阅 帮助LWN继续出版 作者 Jake Edge 2018年12月12日 Linux管道工会议 在2018年Linux Plumbers大会 LPC 的RDMA微型会议上 J

随机推荐

  • spring boot最新教程(五):404错误500错误统一处理

    Spring Boot默认使用嵌入式Tomcat 默认没有页面来处理404等常见错误 因此 为了给用户最佳的使用体验 404 500等常见错误需要我们自定义页面来处理 我们需要用org springframework boot contex
  • 威动服务器如何添加文件夹,威动服务器如何设置

    威动服务器如何设置 内容精选 换一换 华为云提供两种连接方式通过SQL Server客户端连接实例 非SSL连接和SSL连接 其中 SSL连接实现了数据加密功能 具有更高的安全性 安装SQL Server客户端请参见如何安装SQL Serv
  • 如何使用 Docker 部署 Caddy Web 服务器

    Caddy是一种流行的现代 Web 服务器 专为高性能和内存安全而设计 它是用 Go 编写的 运行时没有依赖关系 内置支持使用 Markdown 进行静态站点渲染 并提供自动 HTTPS Caddy 专注于提供简单的服务器管理体验 默认情况
  • Vue + Element UI 前端篇(十一):第三方图标库

    Vue Element UI 实现权限管理系统 前端篇 十一 第三方图标库 使用第三方图标库 用过Elment的同鞋都知道 Element UI提供的字体图符少之又少 实在是不够用啊 幸好现在有不少丰富的第三方图标库可用 引入也不会很麻烦
  • HDFS常用命令

    1 hdfs dfs与hadoop fs 命令的形式 hdfs dfs linux命令 这与linux中命令操作是一样的 hadoop fs等同于hdfs dfs 2 Hadoop命令 hadoop classpath 打印当前hadoop
  • 程序员的自我修养(九)虚拟内存空间

    进程的虚拟地址 每个程序被运行起来以后 它将拥有自己独立的虚拟地址空间 这个虚拟地址空间的大小由计算机的硬件平台决定 具体的说是由CPU的位数决定 对于Linux系统来说 它的进程虚拟空间的划分 1GB 操作系统 3GB 进程 对于Wind
  • derby mysql 性能_derby的三大缺陷

    derby数据库的嵌入式特性让人很流口水 但是 我刚打算将其用进我的项目中 却发现它没有好的分页查询方式 每次都返回所有符合条件的记录 oracle有rownum mysql有limit sqlserver好歹也有个top 汗啊汗 看来不爽
  • 【ROS入门学习01

    ROS命令行工具的使用 可以配合古月居的ROS入门教程来学习实践 文章目录 ROS命令行工具的使用 一 roscore 二 rosrun 三 rqt graph 四 rosnode 五 rostopic 六 rosmsg 七 rosserv
  • 客观面试题--35.Mybatis和hibernate的优缺点?

    Hibernate Hibernate 是当前最流行的ORM框架 对数据库结构提供了较为完整的封装 Mybatis Mybatis同样也是非常流行的ORM框架 主要着力点在于POJO 与SQL之间的映射关系 其次具体从几个方面说一下两者的区
  • 自己动手部署以太坊联盟链

    一个区块链学习项目 GitHub https github com xianfeng92 Love Ethereum 假设已经在Ubunbu 14 04 LTS上安装好了以太坊客户端Geth 使用Geth部署以太坊联盟链 以太坊Geth客户
  • java jvm dump文件_干货分享丨jvm系列:dump文件深度分析

    摘要 java内存dump是jvm运行时内存的一份快照 利用它可以分析是否存在内存浪费 可以检查内存管理是否合理 当发生OOM的时候 可以找出问题的原因 那么dump文件的内容是什么样的呢 JVM dump java内存dump是jvm运行
  • 45_SDIO基础知识

    目录 SDIO协议简介 SDIO设备分类 SD卡物理结构 SD卡寄存器列表 SDIO总线拓扑 SDIO总线 SDIO总线协议 SDIO命令 命令格式 命令类型 响应 SD卡的操作模式 卡识别模式 数据传输模式 STM32 SDIO功能框图
  • vue中element 的 el-table数据量大时,出现卡顿情况解决办法

    一 安装 npm install umy ui 二 引入js和css import umy ui lib theme chalk index css 引入样式 import UTable UTableColumn from umy ui V
  • 时间戳问题汇总

    大家好 我刚接触流媒体不久 现在遇到一个非常奇怪的问题 向各位大侠请假 请你们指点 问题是这样的 用一个 VLC 流媒体客户端 去请求流媒体服务器上的数据 但是获得的数据播放速度明显快于1倍速 大概是 timestamp 不对 不知道是服务
  • 关于Qos中常用的CIR、PIR、CBS、PBS、EBS的解释以及用法关系

    CIR Committed Information Rate 承诺信息速率 每秒可通过的速率 计量单位为Kbps 以bit 位为单位 如设置为500Kbps 每8bit位 1Byte 1Kbps 1024bit PIR Peak Infor
  • ERROR: Could not find a version that satisfies the requirement XXX解决方法

    出现问题 ERROR Could not find a version that satisfies the requirement XXX解决方法 找了很久终于找到能解决这种报错的方法了 直接选用pip源并且信任它的来源就可以解决这种问题
  • No grammar constraints (DTD or XML schema) detected for the document

    No grammar constraints DTD or XML schema detected for the document
  • ESP8266与手机App通信(STM32)

    认识模块 ESP8266是一种低成本的Wi Fi模块 可用于连接物联网设备 控制器和传感器等 它具有小巧 高度集成和低功耗的特点 因此在物联网应用中被广泛使用 ESP8266模块由Espressif Systems开发 具有单芯片的封装和多
  • case when 作为条件_sqlserver条件分支case when使用教程

    在sqlserver的条件分支case when有两种写法 1 case 字段 when 值 then 返回值 when 值2 then 返回值2 end 2 case when 条件1 then 返回值1 when 条件2 then 返回
  • 【翻译】 zswap 压缩交换缓存

    您知道吗 LWN net 是一份由订阅者支持的出版物 我们依靠订阅者来维持整个运作 请通过订阅来帮助我们 让 LWN 继续在网络上运行 2013年2月12日 本文由 Seth Jennings 投稿 交换是性能的最大威胁之一 即使在快速固态