compress

Redis之quicklist源码分析

♀尐吖头ヾ 提交于 2020-04-19 21:09:44
一、quicklist简介 Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。 一个列表最多可以包含 2 32 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。 其底层实现所依赖的内部数据结构就是quicklist,主要特点有: 1. list是一个双向链表。 2. 在list的两端追加和删除数据极为方便,时间复杂度为O(1)。 3. list也支持在任意中间位置的存取操作,时间复杂度为O(N)。 在看源码之前(版本3.2.2),我们先看一下quicklist中的几个主要数据结构: 一个quicklist由多个quicklistNode组成,每个quicklistNode指向一个ziplist,一个ziplist包含多个entry元素,每个entry元素就是一个list的元素,示意图如下:                         图1:quicklist 二、quicklist数据结构源码 下面分别看下quicklist、quicklistNode的源码(代码文件是Quicklist.h,ziplist后面文章再分析): quicklist: /* quicklist结构占用32个字节(64位系统),其中字段: head:指向第一个quicklistNode。 tail

443. 压缩字符串

爷,独闯天下 提交于 2020-04-12 12:08:59
给定一组字符,使用原地算法将其压缩。 压缩后的长度必须始终小于或等于原数组长度。 数组的每个元素应该是长度为1 的字符(不是 int 整数类型)。 在完成原地修改输入数组后,返回数组的新长度。 示例 1: 输入:["a","a","b","b","c","c","c"] 输出:返回6,输入数组的前6个字符应该是:["a","2","b","2","c","3"] 说明: "aa"被"a2"替代。"bb"被"b2"替代。"ccc"被"c3"替代。 思路: 遍历list: 如果下一个元素和当前元素一样,ans不变,计数器加一; 如果下一个元素和当前元素不一样,将ans和计数器转型后拼接到结果串后面;然后 ans重置,计数器重置; 1 class Solution(object): 2 def compress3(self, chars): 3 # 设定记录元素的指针 和 写指针 4 anchor = write = 0 5 # 遍历原list 6 for read, c in enumerate(chars): 7 # 如果读到了原list末尾,或者当前字符与后一个字符不同,说明读到了相同字符的末尾 8 if read + 1 == len(chars) or chars[read + 1] != c: 9 # 将记录的元素写到新list中 10 chars[write] =

443. 压缩字符串

倾然丶 夕夏残阳落幕 提交于 2020-04-12 11:55:50
给定一组字符,使用原地算法将其压缩。 压缩后的长度必须始终小于或等于原数组长度。 数组的每个元素应该是长度为1 的字符(不是 int 整数类型)。 在完成原地修改输入数组后,返回数组的新长度。 示例 1: 输入:["a","a","b","b","c","c","c"] 输出:返回6,输入数组的前6个字符应该是:["a","2","b","2","c","3"] 说明: "aa"被"a2"替代。"bb"被"b2"替代。"ccc"被"c3"替代。 思路: 遍历list: 如果下一个元素和当前元素一样,ans不变,计数器加一; 如果下一个元素和当前元素不一样,将ans和计数器转型后拼接到结果串后面;然后 ans重置,计数器重置; 1 class Solution(object): 2 def compress3(self, chars): 3 # 设定记录元素的指针 和 写指针 4 anchor = write = 0 5 # 遍历原list 6 for read, c in enumerate(chars): 7 # 如果读到了原list末尾,或者当前字符与后一个字符不同,说明读到了相同字符的末尾 8 if read + 1 == len(chars) or chars[read + 1] != c: 9 # 将记录的元素写到新list中 10 chars[write] =

使用libjpeg进行图片压缩

偶尔善良 提交于 2020-04-08 17:51:49
简介 由于工作原因,boss下达的任务就大概说了对图片进行压缩寻找比较合理的方式,还举了一个项目中的坑,就是系统原生的Bitmap.compress设置质量参数为100生成图片会变大的坑。所以我打算用一点时间研究研究Bitmap在内存和外存中的情况。首先需要对图片进行压缩,大家都知道图片是Android里面一个大坑,具体的问题有: OOM,一不留神就用OOM来冲冲喜,所以网上就有了很多解决oom问题的建议,但是由于网友的水平不一也导致建议参差不齐。(内存) 图片压缩再加载失真严重,或者压缩率不够达不到项目要求的效果。(外存) 那我今天就要解决的就是通过今天查阅的资料和自己的判断,还有实践归档一下图片在Android上的问题。并且给出自己解决图片压缩问题的解决方案和实际操作。 1、为什么Android上的图片就不如IOS上的? libjpeg是广泛使用的开源JPEG图像库,安卓也依赖libjpeg来压缩图片。但是安卓并不是直接封装的libjpeg,而是基于了另一个叫Skia的开源项目来作为的图像处理引擎。Skia是谷歌自己维护着的一个大而全的引擎,各种图像处理功能均在其中予以实现,并且广泛的应用于谷歌自己和其它公司的产品中(如:Chrome、Firefox、 Android等)。Skia对libjpeg进行了良好的封装,基于这个引擎可以很方便为操作系统、浏览器等开发图像处理功能。

Android中使用libjpeg-turbo进行图片质量压缩过程记录

假装没事ソ 提交于 2020-04-07 21:27:37
项目开发过程中发现Android的质量压缩算法在图片过大,色彩丰富的前提下,压缩的性能不是特别好,经过调查发现Android底层实现使用Skia引擎,封装了了libjpeg图像库。为了适配低版本的Android手机,其内部的压缩算法并没有采用普遍的哈夫曼算法,因为哈夫曼算法比较占CPU,从而选择了其他的算法B,而算法B的效果并没有达到项目预期,所以这里研究一下通过自编译libjpeg来使用哈夫曼算法进行图片压缩的操作。 libjpeg-turbo是针对libjpeg库的一个优化版本,具体的介绍可以移步 官方网站 。接下来记录如何编译出对应的so包文件,这里采用Cmake的方式进行。 首先下载libjpeg-turbo 源码 ,将源码中的所有文件拷贝到cpp文件夹目录下: 这里需要注意的是需要把项目的CmakeList文件改变成libjpeg-turbo文件夹下面的CmakeList文件,然后进行编译,就可以在如下目录中产生so文件了: 第二步是要复制对应的头文件到新项目当中,主要的头文件包括如下几个,当然如果调用时候需要用到其他的头文件,那么在复制进去即可: 然后在CmakeList中增加so库链接,连接到我们项目中的so包中去: cmake_minimum_required(VERSION 3.4.1) set(distribution_DIR ../../../../libs)

博客开发日志(1)

折月煮酒 提交于 2020-04-06 18:58:04
前言 博客的编辑功能总算做完了,总的来说还是比较简单的。但是也碰到了很多没有遇到过的技术问题 ,就是下面这个样子 在线编辑器选用mavon-editor,功能基本满足, 使用也比较灵活,增加了自动保存,推送、同步git仓库的功能 目录和文件的管理比较纠结,选用ElementUI或者iview等主流框架,比较熟悉且方便开发。但是相对太厚重,虽说可以按需引入,但是css样式还是需要整个引入或者通过CND加速。 所以为了简单方便不引用过多的外部插件,手写了一个树型控件,还挺简单的 并没有 服务端基本用 fs 模块就能处理。通过接口提供 CRUD 的博客接口 处理图片 写博客免不了要贴图,方便示意且直观,做起来也比较简单,通过接口接受图片转换的base64就行,这样也不用额外引入库 前端 获取File对象做转换 /** * <input type="file" onchange="upload(this)"> */ function upload(input) { const file = input.files[0] const reader = new FileReader() reader.readAsDataURL(file) console.log(reader.result) } 服务端 路由接收到数据后将base64的字符串做处理然后转换为二进制存入缓冲区写入文件 /** *

读写接口

孤人 提交于 2020-04-06 07:09:16
针对一些输入/输出的场景,一般可能会涉及到读/写操作。比如,对一段字符串进行 gzip 压缩,或者解压缩, golang 下主要通过两个接口来实现: 读的接口声明如下: type Reader interface { Read(p []byte) (n int, err error) } 写接口声明如下: type Writer interface { Write(p []byte) (n int, err error) } 结合 compress/gzip 包,我们来了解一下这两个接口。 gzip 中包括两个功能:压缩和解压缩。 解压缩的情况, gzip 提供了 gzip.Reader 对象,用来从压缩的内容中读区被压缩前的原始内容。对象的创建函数如下: func NewReader(r io.Reader) (*Reader, error) 压缩的情况也类似: func NewWriter(w io.Writer) *Writer 对一个被 gzip 压缩的字符串,该如何转换为 io.Reader / io.Writer 呢? bytes 包提供了 Buffer 对象,就实现了这两个接口。 拿压缩的情况j举例: func gzip(src string) string { srcBuffer := bytes.NewBuffer() gzipWriter := gzip

Redis数据结构——quicklist

风流意气都作罢 提交于 2020-04-05 17:55:16
Redis数据结构——quicklist 之前的文章我们曾总结到了Redis数据结构——链表和Redis数据结构——压缩列表这两种数据结构,他们是Redis List(列表)对象的底层实现方式。但是考虑到链表的附加空间相对太高,prev 和 next 指针就要占去 16 个字节 (64bit 系统的指针是 8 个字节),另外每个节点的内存都是单独分配,会加剧内存的碎片化,影响内存管理效率。因此Redis3.2版本开始对列表数据结构进行了改造,使用 quicklist 代替了 ziplist 和 linkedlist. 一、基本结构# quicklist 实际上是 zipList 和 linkedList 的混合体,它将 linkedList 按段切分,每一段使用 zipList 来紧凑存储,多个 zipList 之间使用双向指针串接起来。 Copy typedef struct quicklistNode { struct quicklistNode *prev; //上一个node节点 struct quicklistNode *next; //下一个node unsigned char *zl; //保存的数据 压缩前ziplist 压缩后压缩的数据 unsigned int sz; /* ziplist size in bytes */ unsigned int count

Linux 解压与压缩

萝らか妹 提交于 2020-02-27 15:21:35
Linux下有非常多的压缩打包方式,这些方式的打包解包等命令都有区别。 . tar 解包 : tar xvf FileName.tar 打包 : tar cvf FileName.tar f1 f2 dir1 ( tar是打包,不是压缩!) . gz 解压1: gunzip FileName.gz 解压2: gzip -d FileName.gz 压缩: gzip FileName . tar . gz /. tgz 解压: tar zxvf FileName.tar.gz 解压: tar zxf FileName.tar.gz – C /temp/ 解压至指定路径 压缩: tar zcvf FileName.tar.gz DirName . bz2 /. bz 解压1: bzip2 -d FileName.bz2 解压2: bunzip2 FileName.bz2 压缩: bzip2 -z FileName tar . bz2 / tar . bz 解压: tar jxvf FileName.tar.bz2 压缩: tar jcvf FileName.tar.bz2 DirName .Z 解压: uncompress FileName.Z 压缩: compress FileName . tar.Z 解压: tar Zxvf FileName.tar.Z 压缩: tar Zcvf

logroate的使用

那年仲夏 提交于 2020-02-27 14:08:37
lograte配置参数 daily 指定转储周期为每天 weekly 指定转储周期为每周 monthly 指定转储周期为每月 rotate 转储次数,超过将会删除最老的那一个 missingok 忽略错误,如“日志文件无法找到”的错误提示 dateext 切换后的日志文件会附加上一个短横线和YYYYMMDD格式的日期 dateformat -%Y%m%d%s #配合dateext 一起使用,修改后缀格式 compress 通过gzip 压缩转储旧的日志 delaycompress 当前转储的日志文件到下一次转储时才压缩 notifempty 如果日志文件为空,不执行切割 sharedscripts 只为整个日志组运行一次的脚本 prerotate/endscript 在转储以前需要执行的命令可以放入这个对,这两个关键字必须单独成行 postrotate/endscript 在转储以后需要执行的命令可以放入这个对,这两个关键字必须单独成行 size  size当日志文件到达指定的大小时才转储,Size 可以指定 bytes (缺省)以及KB (sizek)或者MB (sizem). 以nginx日志为例子 cat /etc/logroate.d/nginx /data/logs/nginx/*.log { su root root #切换用户 daily #按天执行 rotate