自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(154)
  • 问答 (2)
  • 收藏
  • 关注

原创 聊聊go语言逃逸分析

1. 从一个例子开始下面是一段c代码,函数getStr生成了a-z的串,我们分别在函数内部和main中对字串进行了输出。//例1.1#include <stdio.h>//返回字串char* getStr(){ //char数组 函数栈上分配内存 char buf[27]; int i; //产生a-z的串 for (i=0; i<sizeof(buf)-1; i++){ buf[i] = i + 'a';

2021-10-13 19:06:33 486 2

原创 go语言select语句中的求值问题

1. 从一个问题说起package mainimport ( "fmt")var ch0 = make(chan int)var ch1 = make(chan int)var chs = [](chan int){ch0, ch1}func getCh(i int) chan int{ fmt.Printf("get ch:%d\n", i) return chs[i]}func getNum(i int) int{ fmt.Printf("get num:%d\n",

2021-09-14 16:37:05 439

原创 PDF Explained(翻译)第七章 文档元数据和导航

本文是对PDF Explained(by John Whitington)第七章《 Document Metadata and Navigation》的摘要式翻译,并加入了一些自己的理解。本章我们讨论四个辅助数据,这些数据并不影响PDF的显示。定位(Destinations):定义文件中位置的数据结构。它们可用于指定书签或超链接指向的位置。书签就是文档的目录。XML元数据: 流数据,包含了特定格式的XML文件,一些与文档信息字典相同的元数据,以及其他字段。文件附件:允许像电子邮件附件那将将整个文件

2021-08-17 17:20:46 599

原创 PDF Explained(翻译)第六章 文本和字体

本文是对PDF Explained(by John Whitington)第六章《Text And Fonts》的摘要式翻译,并加入了一些自己的理解。文本状态文本状态相关的操作符和参数如下表所示:操作符操作数(参数)描述默认值例TccharSpaceTc将字符间距设为charSpace0TwwordSpaceTw将字符间距设为wordSpace0TzscaleTz将水平缩放设置为scale/100100(正常大小)TLleadin

2021-07-26 11:45:13 704

原创 PDF Explained(翻译)第四章 文档结构

本文是对PDF Explained(by John Whitington)第四章《Document Structure》的摘要式翻译。本章我们来看PDF的逻辑结构,涉及trailer字典,文档目录(document catalog)和页面树以及PDF中两种常见结构:文本字符串和日期。一个典型的PDF文档逻辑结构如下图所示:Trailer字典这份字典位于文件尾部而不是文件的主体中,如果程序想要读取PDF文档,首先要做的就是处理trailer字典。字典中的重要条目如下表所示,*表示必选条目。

2021-07-21 16:58:10 315 1

原创 PDF Explained(翻译)第三章 文件结构

本文是对PDF Explained(by John Whitington)第三章《File Structure》的摘要式翻译。文件布局一个简单全法的PDF文件按顺序可分为如下四部分:header,给出了PDF版本号body,包含了页面,图形内容,和许多辅助信息,它们都编码为一系列对象。交叉引用表,列出了每个对象在文档中的位置,便于随机访问。trailer,包含一个字典,用于定位文件中的各个部分,同时列出了可以在不处理整个文件的情况下读取的各种元数据。再来看下第二章中“Hello World

2021-07-14 16:53:38 476

原创 PDF Explained(翻译)第二章 构建一个简单的PDF

本文是对PDF Explained(by John Whitington)第二章《Building a Simple PDF》的摘要式翻译。本章我们将使用文本编辑器手动构建PDF内容。然后我们将使用 pdftk将其转换为有效的PDF文件,并在PDF查看器中进行查看。关于PDFTK(THE PDF TOOLKIT)pdftk是一个开源的命令行程序,它的功能有:合并分割PDF文档旋转PDF页面加解密填充PDF表单加水印和图章打印和修改PDF元数据(metadata)添加附加基本的PDF

2021-07-09 17:21:01 426 1

原创 PDF Explained(翻译)第一章 简介

本文是对PDF Explained(by John Whitington)的摘要式翻译。一点历史PDF的发展PDF起初是Adobe的一个内部项目,其目标是创建一种平台无关的文档交换方式。当时PostScript已经在印刷界非常流行,但在当时的电脑屏幕显示上还不是很实用–特别是随机访问方面(如果需要渲染一个PostScript文档的第50页,就必须先处理好前49页)。项目的想法是使用PostScript图片语言的子集加上一些辅助数据来创建一种结构化的语言,可以用于在任何计算机上查看(或打印)文档。P

2021-07-08 16:36:38 357 1

原创 PDF字体简介

1. PDF字体概述PDF中的文本可以是任何字体。所有的PDF查看器都必须支持5种字体(Times, Helvetica, Courier, Symbol and ZapfDingbats),这些字体可以在任何文档中直接使用。如果想使用其它字体,有如下三种方法:1) 只指明字体的名子。如果使用者的设备上没有该字体,则会使用标准字体显示。2) 内嵌字体当整个字体文件放入PDF文件中。这保证了该字体在任何设备上都可以使用。相应的问题是,这会使用PDF文件变得比较大。3) 内嵌字体子集只在文档中包含

2021-07-05 16:26:39 1231

原创 PDF新晋开发者须知

本文是对What new PDF developers need to know的摘要式翻译,同时加入了一些自己的理解。不要将PDF文件当作“文件”当你开始学习HTML时,你可以使用文本编辑器打开一个文件,修改它,然后看看发生了什么。但是你无法对一个PDF文件这样做。 PDF文件本质上是一个二进制数据结构,许多信息是无法直接看到的。哪怕你只修改了其中一个字节都有可能破坏整个文件。PDF即对象(object)PDF文件中包含了大量PDF对象(PDF object)。每个对象有唯一的ID,ID格式如下

2021-07-02 14:50:24 382 2

原创 《架构简洁之道》思维导图及目录导航

1. 全书思维导图部分结构按笔者理解做了调整2. 目录导航第1部分 概述第2部分 从基础构件开始:编程范式第3部分 设计原则第4部分 组件构建原则第5部分 软件架构第6部分 实现细节

2021-06-23 16:31:39 449 2

原创 架构整洁之道 30~34章读书笔记

第6部分 实现细节第30章 数据库只是实现细节如果就数据库与整个系统架构的关系打个比方,它们之间就好比是门把手和整个房屋架构的关系。一个优秀的架构师是不会让实现细节污染整个系统架构的。关系型数据库数据按行组织成表结构本身并没有什么系统架构意义上的重要性。应用程序的用例不应该知道,也不应该关心这么低层次的实现细节,需要了解数据表结构的代码应该被局限在系统架构的最外圈、最低层的工具函数中。很多数据访问框架允许将数据行和数据表以对象的形式在系统内部传递。这么做在系统架构上来说是完全错误的,这会导致程序

2021-06-21 14:37:31 166 1

原创 架构整洁之道 15~29章读书笔记

第5部分 软件架构第15章 什么是软件架构软件架构师自身需要是程序员,并且必须一直坚持做一线程序员,绝对不要听从那些说应该让软件架构师从代码中解放出来以专心解决高阶问题的伪建议。也许软件架构师生产的代码量不是最多的,但是他们必须不停地承接编程任务。如果不亲身承受因系统设计而带来的麻烦,就体会不到设计不佳所带来的痛苦,接着就会逐渐迷失正确的设计方向。设计软件架构的目的,就是为了在工作中更好地对这些组件进行研发、部署、运行以及维护。如果想设计一个便于推进各项工作的系统,其策略就是要在设计中尽可能长时间

2021-06-18 16:10:01 910 2

原创 架构整洁之道 12~14章读书笔记

第4部分 组件构建原则如果说SOLID原则是用于指导我们如何将砖块砌成墙与房间的,那么组件构建原则就是用来指导我们如何将这些房间组合成房子的。第12章 组件组件是软件的部署单元,是整个软件系统在部署过程中可以独立完成部署的最小实体。在编译运行语言中,组件是一组二进制文件的集合。而在解释运行语言中,组件则是一组源代码文件的集合。无论采用什么编程语言来开发软件,组件都是该软件在部署过程中的最小单元。但无论采用哪种部署形式,设计良好的组件都应该永远保持可被独立部署的特性,这同时也意味着这些组件应该可以被

2021-06-10 17:14:09 1154 8

原创 架构整洁之道 7~11章读书笔记

第3部分 设计原则如果建筑的架构设计不佳,那么其所用的砖头质量再好也没有用。这就是SOLID设计原则所要解决的问题。SOLID原则的主要作用就是告诉我们如何将数据和函数组织成为类,以及如何将这些类链接起来成为程序。我们为软件构建中层结构的主要目标如下:使软件可容忍被改动。使软件更容易被理解。构建可在多个软件系统中复用的组件。SOLID原则应该直接紧贴于具体的代码逻辑之上,这些原则是用来帮助我们定义软件架构中的组件和模块的。SRP:单一职责原则一个软件系统的最佳结构高度依赖于开发这个系统

2021-06-09 17:32:15 962 16

原创 架构整洁之道 3~6章读书笔记

第2部分 从基础构件开始:编程范式第3章 编程范式总览三个编程范式包括:结构化编程(structured programming)、面向对象编程(object-oriented programming)以及函数式编程(functional programming)。结构化编程结构化编程对程序控制权的直接转移进行了限制和规范。面向对象编程面向对象编程对程序控制权的间接转移进行了限制和规范。函数式编程函数式编程对程序中的赋值进行了限制和规范。仅供思考没有一个范式是增加新能力的。也就是说,每个

2021-06-08 11:00:25 298 8

原创 架构整洁之道 1~2章读书笔记

第1部分 概述第1章 设计与架构究竟是什么设计(Design)与架构(Architecture)二者没有任何区别。一丁点区别都没有!“架构”这个词往往使用于“高层级”的讨论中。这类讨论一般都把“底层”的实现细节排除在外。而“设计”一词,往往用来指代具体的系统底层组织结构和实现的细节。但是,从一个真正的系统架构师的日常工作来看,这样的区分是根本不成立的。目标是什么软件架构的终极目标是,用最小的人力成本来满足构建和维护该系统的需求。一个软件架构的优劣,可以用它满足用户需求所需要的成本来衡量。龟兔赛

2021-06-04 16:30:40 278 11

原创 db2gorm -- 将mysql数据表转为gorm struct

0. 为什么写这样一个工具找到的开源工具功能比较多,用起来也复杂些自己定制的更适合自己的项目学习go时间不长,写一款工具也是练习的过程项目地址https://github.com/qmhball/db2gorm1. 功能根据数据库表生成gorm需要的struct。支持指定单表生成,也可以全库生成。比如有如下数据表:Table: UserCreate Table: CREATE TABLE `User` ( `id` int(10) unsigned NOT NULL AUTO_I

2021-06-01 11:17:43 1980 8

原创 gorm hook使用中的问题及核心源码解读

本文针对的是gorm V2版本。hook官方文档可以点击这里,本文旨在对官方文档作一些补充说明。下文中所有的DB均指gorm.Open返回的DB对象。DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})1. hook作用的对象hook只能定义在model上,不能定义在gorm.DB上。假设我们有User表,对应model如下,则可以定义BeforeCreate hook,用于插入数据前的检查。type User struct { I

2021-05-24 10:32:09 2501 2

原创 使用logrus记录gorm sql

gorm可以方便的输出执行的sql或慢查询。logrus是常用的日志组件,如何将gorm输出的sql通过logrus记录到日志中呢?1. 代码实现我们先看代码。思路:使用logrus,实现gorm/logger.Writer接口var DB *gorm.DB//定义自己的Writertype MyWriter struct { mlog *logrus.Logger}//实现gorm/logger.Writer接口 func (m *MyWriter)Printf(format st

2021-05-17 10:03:03 1379 6

原创 如何让gorm输出执行的sql

1. 打印所有sql在打开连接时设置日志级别为InfoDB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{ Logger:logger.Default.LogMode(logger.Info),})2. 打印单条sql在操作前加Debug(), 相当于将临时将日志级别改为InfoDB.Debug().Where("ID = ?", 52).First(&newData)//输出//[0.773ms] [rows:1] SE

2021-05-14 16:34:07 10905 3

原创 logrus中输出文件名、行号及函数名

日志中输出文件名,行号及函数名是个比较有用的功能,那么在logrus中如何作到呢?1. 在处带Formatter中输出logrus有两个片带的Formatter,分别是:TextFormatter和JSONFormatter。要在这两个Formatter中输出文件名,行号和函数名,只需要设置logrus.SetReportCaller(true)1.1 在TextFormatter中输出func Demo(){ logrus.Info("i'm demo")}func main(){

2021-05-11 15:20:13 6498 2

原创 logrus自定义日志输出格式

1. 设置日志格式的方法logrus中,使用如下方法设置日志格式func SetFormatter(formatter Formatter) 其中Formatter是一个接口type Formatter interface { Format(*Entry) ([]byte, error)}所以,实现自定义日志格式,本质上就是实现Formatter接口,然后通过SetFormatter方式将其告知logrus。2. 已有Formatterlogrus包中自带两种Formatter,分别是

2021-05-11 14:23:36 5024 2

原创 go中类型的相等(==)及可比较规则

本文主要参考了The Go Programming Language Specification中的Comparison_operators。加入了自己的一些理解和示例。如果两个变量是可比较的(使用==或!=),那它们必可以相互赋值。这意味着可比较的两个变量必须是同一类型,或者他们的底层类型相同。1. 布尔类型可比较2. 整型可比较3. 浮点数可比较4. 复数可比较。5. 字串可比较6. 指针值可比较。两个指针指向同一个变量,则这两个指针相等,或者两个指针同为nil,它们也相等。

2021-02-09 15:21:09 2223 1

原创 《go in action》第5章(Go语言的类型系统)读书笔记

5.1 用户定义的类型不使用字段名创建结构类型的值,这咱形式下值的顺序很重要。type user struct { name string age int email string}lisa := user{"Lisa", 20, "[email protected]"}两种不同类型的值即便相互兼容,也不能互相赋值。编译器不会对不同类型的值做隐式转换。type Duration int64func main() { var dur Duration dur = int64(10

2021-02-07 17:01:49 145

原创 《go in action》第4章读书笔记

4.1 数组的内部实现和基础功能4.1.1 内部实现数组是一个长度固定的数据类型。4.1.2 声明和初始化一旦声明,数组里存储的数据类型的数组长度就都不能改变了。//声明一个包含5个元素的整型数组var array [5]int//声明一个包含5个元素的整型数组, 用初值初始化每个元素array := [5]int{10,20,30,40,50}在Go语言中声明变量时,总会使用对应类型的零值来对变量进行初始化。数组也不例外。如果使用…替代数组的长度,Go语言会根据初始化时数组元素的数

2021-02-03 14:22:22 99

原创 从一个翻页查询说起

1. 问题有如下数据表:CREATE TABLE `user` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `nick` varchar(255) NOT NULL DEFAULT '', `image_url` varchar(255) NOT NULL DEFAULT '', `exp` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '经验值', `create_time` tim

2020-12-28 18:33:18 119

原创 《代码之外的功夫:程序员精进之路》读书笔记

第1章 善用设计原型,探索项目创意本章背景:你是能力很强的程序员,并且正在发挥技术特长,运用速成原型法帮助人们探索新的产品创意。尽早生成可工作的软件,可以令产品设计变成交互式协作过程。高效的反馈环有利于快速识别潜在的不良设计,并对此提出解决方案,以免日后在更关键的阶段浪费大量时间和精力。1.2 利用线框图表达功能需求不要花费过长时间去讨论子系统(书中实际例子为推荐系统)的完美实现方式,而应该先集中精力寻找“最简单可行的方法”。1.3 编程之初立即搭建测试系统第一次发布的真正目的是创建一个可用的系

2020-12-14 10:02:48 326 1

原创 redis stream中pending数据的处理

1. pending数据的产生在消费者组模式下,当一个消息被消费者取出,为了解决组内消息读取但处理期间消费者崩溃带来的消息丢失问题,STREAM 设计了 Pending 列表,用于记录读(XREADGROUP)取但并未处理完毕(未ACK)的消息。2. 对pending数据的几种处理方式下面的讨论基于几点:面向的场景为多个无差别消费者(每个消费者名子相同,功能相同)在同一group下消费任务。我们要保证的是,每个任务至多只做一次。代码实现是在使用redis stream实现队列服务一文的封装基础

2020-11-12 14:39:19 3989

原创 使用redis stream实现队列服务

1. stream类型Redis5.0引入了Stream类型。该Stream类型的出现,几乎满足了消息队列具备的全部内容,包括但不限于:消息ID的序列化生成消息遍历消息的阻塞和非阻塞读取消息的分组消费未完成消息的处理关于stream的具体介绍可以参见:Introduction to Redis StreamsStream 类型2. 队列接口简介我们基于redis stream实现了一个基础的,类似beanstalk的队列服务。用于多个无差别的消费者从一个队列消费任务的情况。如果

2020-11-12 09:55:37 1006

原创 php7数组的实现及部分源码分析

1.基本概念1.1 数组的语义本质上PHP数组是一个有序字典,它必须同时满足以下2个条件:语义一:PHP数组是一个字典,存储着键-值(key-value)对。通过键可以快速地找到对应的值,键可以是整型,也可以是字符串。语义二:PHP数组是有序的。这个有序指的是插入顺序,即遍历数组的时候,遍历元素的顺序应该和插入顺序一致,而不像普通字典一样是随机的。1.2 数组的概念PHP的数组zend_array对应的是HashTable。HashTable(哈希表)是一种通过某种哈希函数将特定的键映射到特

2020-09-28 12:31:35 727 5

原创 php7垃圾回收机制及相关源码解读

0. gc的基本结构0.1 zend_refcounted_h在《php7的引用计数》一文中,我们说过,php7的复杂类型,像字符串、数组、引用等的数据结构中,头部都有一个gc,变量的引用计数维护在这个gc中。gc是zend_refcounted_h类型的,其定义如下://php7.0 Zend/zend_types.htypedef struct _zend_refcounted_h { uint32_t refcount; /* reference c

2020-09-14 18:46:10 980 2

原创 php7 写时复制

1. 什么是写时复制在《php7引用计数》的文章中,我们知道,对于复制类型的变量,在赋值时,我们并没有重新复制一份数据,而是让新变量的zend_value中相应的指针指向原来的数据,同时增加引用计数。赋值后,如果其中一个变量试图改变数据内容,就需要重新拷贝一份原数据,同时断开zend_value指向,并改变引用计数。这个过程我们称为写时复制。下面来看一个例子:$a = range(0,2);$b = $a;xdebug_debug_zval('a');xdebug_debug_zval('b'

2020-09-01 18:30:46 207

原创 php7引用计数

1. 什么是引用计数在《php7 zval及变量存储方式》的2.3节中我们说到,对于复杂类型的变量(string,array,object,resource等),我们会将其具体的值记录在单独的内存区域,再由zend_value中相应的指针指向该内存区域。指向该内存区域的指针数量,即为引用计数。引用计数是服务于垃圾回收的机制的。当引用计数为0,相应的内存区域就可以回收了。官方手册中有关于引用计数的阐述,不过应该是针对5.*版本的,和7.*相比,大体思想是一样的,但实现和使用xdebug_debug_zv

2020-08-28 16:00:51 567 2

原创 php7的zval及变量存储方式

Zval是PHP中最重要的数据结构之一,它包含了PHP中变量的值和类型相关信息。1. zval1.1 zval的结构(zend_types.h)typedef struct _zval_struct zval;struct _zval_struct { zend_value value; /* value */ union { struct { ZEND_ENDIAN_LOHI_4(

2020-08-20 10:15:23 600

原创 redis6.0 客户端缓存(Client side caching)及实践

1. 什么是客户端缓存(Client side caching)通常的缓存会放在应用和DB之间,比如redis。客户端缓存是指在应用服务内部再加一层缓存,也就是内存缓存,从而进一步提升访问速度。2. redis 6.0为此做了什么2.1 client cache的问题client cache的问题是缓存应该何时失效,更确切的说是如何保持与远端数据的一致性。为client cache设置过期时间是一个选择,但时间设置多久是一个问题。太长会有时效性问题,太短缓存的效果会打折扣。2.2 redis

2020-07-24 19:08:15 1981

原创 《Go语言入门经典》目录导航及思维导图

1. 目录导航第1章起步第2章理解类型第3章理解变量第4章使用函数第5章控制流程第6章数组、切片和映射第7章使用结构体和指针第8章创建方法和接口第9章使用字符串第10章处理错误第11章使用Goroutine第12章通道简介第13章使用包实现代码重用第14章Go语言命名约定第15章测试和性能第16章调试第17章使用命令行程序第18章创建HTTP服务器第19章创建HTTP客户端第20章处理JSON第21章处理文件第22章正则表达式简介第23章Go语言时间编程第24

2020-07-10 16:49:19 379

原创 go抽象的生产者消费者模型

这是一个单一生产者,多个消费者的模型。对之前的代码做了改进。目的:包装成包的形式。包的名子叫pc, producer/consumer的简写。使用者只需要写自己实际的生产逻辑和消费逻辑即可。1. 实现package pcimport ( "sync")type Task struct { Data string}type AbstructPC struct { ConsumerNum int ChanLen int Tasks chan Task

2020-07-09 18:23:26 233

原创 go实现生产者消费者模型

这是一个单一生产者,多消费者的模型。该模型主要实现了任务调度和同步。实际使用时需要修改的内容如下:type Task struct{} //自己实际需要的数据结构producer() //实际生产数据逻辑consumer() //实际处理逻辑main()中的consumerNum(消费者个数), channelLen(通道长度)也可根据实际需要修改代码如下:package mainimport ( "fmt" "sync")type Task struct { Dat

2020-07-08 18:45:10 712 2

原创 《Go语言入门经典》23章读书笔记

第23章 Go语言时间编程23.1 时间元素编程要使用Go语言打印计算机中的当前时间,可使用函数Now。import( "time")time.Now()23.2 让程序休眠time.Sleep(3 * time.Second)23.3 设置超时时间要在特定的时间过后执行某项操作,可使用函数After。package mainimport ( "fmt" "time")func main() { fmt.Println("You have 2 seconds

2020-07-07 16:08:10 204

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除