每日新闻

每日新闻

GoCN每日新闻资讯
有问必答

有问必答

Go相关的问题,技术相关的问题
文章分享

文章分享

技术文章分享,让知识传播给更多的人
招聘应聘

招聘应聘

为Gopher服务的招聘应聘平台

聊聊图数据库和图数据库的小知识 Vol.02

NebulaGraph 发表了文章 • 0 个评论 • 368 次浏览 • 2020-01-15 10:27 • 来自相关话题

about graph database


2010 年前后,对于社交媒体网络研究的兴起带动了图计算的大规模应用。


2000 年前后热门的是 信息检索分析 ,主要是 Google 的带动,以及 Amazon 的 e-commerce 所用的协同过滤推荐,当时 collaborative filtering也被认为是 information retrieval 的一个细分领域,包括 Google 的 PageRank 也是在信息检索领域研究较多。后来才是 Twitter,Facebook 的崛起带动了网络科学 network science的研究。


图理论和图算法不是新科学,很早就有,只是最近 20 年大数据,网络零售和社交网络的发展, big datasocial networkse-commerce 、IoT让图计算有了新的用武之地,而且硬件计算力的提高和分布式计算日益成熟的支持也使图在高效处理海量关联数据成为可能。


上文摘录了#聊聊图数据库和图数据库小知识# Vol.01 的【图数据库兴起的契机】,在本次第二期#聊聊图数据库和图数据库小知识#我们将了解以下内容,如果有感兴趣的图数据库话题,欢迎添加 Nebula 小助手微信号:NebulaGraphbot 为好友进群来交流图数据库心得。


本文目录



  • 图数据库和图数据库设计

    • 传统数据库通过设计良好的数据结构是不是可以实现图数据库的功能

    • 图数据库会出于什么考虑做存储计算分离

    • 数据量小,业务量小的情况下,是否单机部署图数据库性能也不错。

    • 图数据库 shared-storage 和 shared-nothing 的比较

    • 图数据库顶点和边输出及超级顶点输出优化

    • 如何处理图数据库中大数据量的点?



  • Nebula Graph 实践细节

    • Nebula Graph 元数据(Meta Service)使用 etcd 吗?

    • Nebula Graph Cache 位于那一层

    • Nebula Graph 集群中的 Partition 多大

    • 如何理解 Nebula Graph Partition




图数据库和图数据库设计


在这个部分,我们会摘录一些图数据库设计通用的设计思路,或者已有图数据库的实践思考。


传统数据库通过设计良好的数据结构是不是可以实现图数据库的功能


图数据库相对传统数据库优化点在于,数据模型。传统数据库是一个关系型,是一种表结构做 Join,但存储结构表明了很难支持多度拓展,比如一度好友,两度好友,一度还支持,使用一个 Select 和 Join 就可完成,但是二度查询开销成本较大,更别提多度 Join 查询开销更大。图数据库的存储结构为面向图存储,更利于查询多度关系。特别的,有些图上特有的操作,用关系型数据库比较难实现和表达,比如最短路径、子图、匹配特定规则的路径这些。


图数据库会出于什么考虑做存储计算分离


存储与计算分离主要出于以下四方面的考虑:



  1. 存储和计算资源可以独立扩展,使资源利用更充分,达到缩减成本的目的。

  2. 更容易利用异构机型。

  3. 解耦计算节点,计算资源可以更大程度地做到线性扩展。基于之前的项目经历,存储计算不分离的分布式架构,计算能力的水平扩展会比较不方便。举个例子,在好友关系这种场景——基于好友关系查询再做一些排序和计算,在某个节点查询执行过程中需要去其他节点获取数据,或者将某个子计算交给其他节点,如果执行过程中需要的数据存储在本地,相较存储计算分离效率可能会高;但当涉及到和其他节点通信问题时,为了扩容计算资源而增加的机器会使得计算过程中的网络开销相应增加,抵消了相当一部分的计算能力。如果存储计算分离,计算和存储一对一,不存在节点越多网络通讯开销越大的问题。

  4. Nebula Graph在存储层提供基于图的查询接口,但不具备运算能力,方便对接外部的批量计算,比如 Spark,可以将图存储层当作为图索引存储,直接批量扫描、遍历图自行计算,这样操作更灵活。存储层支持做一些简单的过滤计算,比如找寻 18 岁好友等过滤操作。


数据量小,业务量小的情况下,是否单机部署图数据库性能也不错。


单机按分布式架构部署,有一定网络开销因为经过网卡,所以性能还行。一定要分布式架构部署的原因在于强一致、多副本的业务需求,你也可以按照业务需求部署单副本。


图数据库 Shared-storage 和 Shared-nothing 的比较


【提问】对于图数据库来说,是不是 shared-storage 相比 shared-nothing 方式更好呢。因为图的节点间是高度关联的,shared-nothing 方式将这种联系拆掉了。对于多步遍历等操作来说,需要跨节点。而且由于第二步开始的不确定性,要不要跨节点好像没法提前通过执行计划进行优化。


【回复】交流群群友 W:errr,单个 storage 能不能放下那么多数据,特别数据量增加了会是个比较麻烦的问题。另外第二步虽然是随机的,但是取第二步数据的时候可以从多台机器并发


【回复】交流群群友 W:主要的云厂商,比如 AWS 的共享存储可以到 64 T,存储应该够,而且这种方式存储内部有多副本。顺便提一句:AWS 的 Neptune 的底层存储用的也是 Aurora 的那个存储。网络这块的优化,可参考阿里云的 Polarstore,基本上网络已经不是什么问题了。


image.png


此外,“第二步虽然是随机的,但是取第二步数据的时候可以从多台机器并发吧”这个倒是,Nebula 有个 storage server 可以做这个事情,但逻辑上似乎这个应该是 query engine 应该干的。


【回复】交流群群友 W:“网络这块的优化,可参考阿里云的 polarstore,基本上网络已经不是什么问题了。” 网络这问题,部署环境的网络不一定可控,毕竟机房质量参差不齐,当然云厂商自己的机房会好很多。


【回复】交流群群友 W:这个确实。所以开源的创业公司走 shared-nothing,云厂商走 shared-storage,也算是都利用了各自的优势


【回复】交流群群友 S:其实,shared-storage 可以被看成是一个存储空间极大的单机版,并不是一个分布式系统


【回复】交流群群友 W:嗯嗯。不过 Neptune 那种跟单机版的区别在于计算那部分是可扩展的,一写多读,甚至 Aurora 已经做到了多写。不过就像前面所说的,开源的东西基于那种需定制的高大上存储来做不现实。想了下拿 AWS 的存储做对比不大合适,存储内部跨网络访问的开销还是一个问题,拿 Polarstore 这种 RDMA 互联更能说明。可能 2 种方案都差不多,本质上都是能否减少跨网络访问的开销。


图数据库顶点和边输出及超级顶点输出优化


【提问】请教一个问题。Nebula 的顶点和出边是连续存放的。那么在查询语句进行 IO 读取时,是顶点和出边会一起读出来呢,还是根据查询语句的不同而不同?


【回复】交流群群友 W:会一个 block 一起读出来


【回复】交流群群友 W:恩恩。对于 supernode 这种情况,有没有做什么优化?Titian/Janusgraph 有一个节点所有边的局部索引,Neo4j 应该有在 object cache 中对一个节点的边按照类型组织


【回复】交流群群友 S:Nebula 也是用 index 来解决这个问题


【回复】交流群群友 W:Neo4j 的 relationship group 是落在存储上的,请教下,Nebula 的这种 index 和 Janusgraph 的 vertex centric 索引类似麽,还是指存储格式里面的 ranking 字段啊


【回复】交流群群友 S:类似于 Janusgraph 的索引,但是我们的设计更 general,支持 multi-column 的索引


【回复】交流群群友 W:ranking 字段其实给客户用的,一般可以拿来放时间戳,版本号之类的。


如何处理图数据库中大数据量的点?


【提问】:Nebula 的存储模型中属性和边信息一起存储在顶点上,针对大顶点问题有好的解决方案吗?属性和关系多情况下,针对这种实体的查询该怎么处理,比如:比如美国最有名的特产,中国最高的人,浙江大学年龄最大的校友


【回复】交流群群友 W:如果可以排序,那分数可以放在 key 上,这样其实也不用 scan 太多了,ranking 字段就可以放这个。要不然还有个办法是允许遍历的过程中截断或者采样,不然很容易爆炸的。


【回复】交流群群友 B:在做实时图数据库的数据模型设计时,尽量避免大出入度的节点。如果避免不了,那至少避免此类节点再往后的 traversal。如果还是避免不了,那别指望这样的查询会有好的性能


【回复】交流群群友 H:单纯的大点如果不从它开始 traversal,其实问题也不大。load 的 unbalance 都是有办法解决的。数据的 unbalance 因为分 part 存储,在分配 part 到 host 时可加入 part 数据量的权重,而 load 的 unbalance,对于读,可通过拓展只读副本 + cache 解决,写的话,可做 group commit,client 也可以做本地 cache。


【回复】交流群群友 B:图数据库的一个查询的性能最终取决于 physical block reads 的数量。不同方案会导致最后 block reads 不一样,性能会有差别。任何一种方案不可能对所有查询都是优化的,最终往往就是 tradeoff。主要看你大部分实际的 query pattern 和数据分布式如何,该数据库实现是否有优化。拆边和不拆边,各有其优缺点。


Nebula Graph 实践细节


在这个部分我们会摘录一些开源的分布式图数据库 Nebula Graph 在实践过程中遇到的问题,或者用户使用图数据库 Nebula Graph 中遇到的问题。


Nebula Graph 元数据(Meta Service)使用 etcd 吗?


不是。Meta Service的架构其实和 Storage Service 架构类似,是个独立服务。


Nebula Graph Cache 位于哪一层


A:KV 那层。目前只有针对顶点的 Cache,顶点的访问具有随机性,如果没有 Cache,性能较差。Query Plan 那层现在还没有。


如何理解 Nebula Graph Partition


partition 是个逻辑概念,主要目的是为了一个 partition 内的数据可以一起迁移到另外一台机器。partition 数量是由创建图空间时指定的 partition_num 确立。而单副本 partition 的分布规则如下


image.png


通过算子:partID%engine_size,而多副本的情况,原理类似,follower 在另外两个机器上。


Nebula Graph 集群中的 Partition 多大


A:部署集群时需要设置 Partition 数,比如 1000 个 Partition。插入某个点时,会针对这个点的id做 Hash,找寻对应的 Partition 和对应 Leader。PartitionID 计算公式 = VertexID % num_Partition


单个 Partition 的大小,取决于总数据量和 Partition 个数;Partition 的个数的选择取决于集群中最大可能的机器节点数,Partition 数目越大,每个 Partition 数据量越小,机器间数据量不均匀发生的概率也就越小。


最后,这里是开源的分布式图数据库 Nebula Graph 的 GitHub 地址:github.com/vesoft-inc/…,欢迎给我们提 issue~~


推荐阅读



一招教你用Go语言爬虫快速精准抓取拉勾职位!!!

有只黑白猫 发表了文章 • 2 个评论 • 492 次浏览 • 2020-01-09 16:51 • 来自相关话题

点击这里,查看源代码等关键重要内容拉 ...查看全部

点击这里,查看源代码等关键重要内容

拉勾

这里分析以拉勾网上的数据为准,通过使用Go语言编写一个拉勾网岗位的爬虫,抓取Go语言的所有岗位,来进行分析。正好我们也是找Go语言工作,顺便用Go语言练练手。

该爬虫比较简单,只需要根据拉勾网的搜索,然后一页页的爬取搜索结果,把结果整理成Excel输出即可。这里我们选取了岗位名称、工作地点、薪水以及招聘公司这几个元素进行爬取,收集这些信息进行分析。

本次分析,爬取了拉勾网上所有Go语言岗位,一共30页,450个岗位进行分析,所以结果也是很有代表性的。

工作地点

微信图片_20200109105450.jpg

从上图来看,450个Go语言的岗位,北京最多,占了186个,其次是上海83个,深圳52个,杭州31个,所以找Go语言的工作还是去北京、上海、深圳这些一线大城市,尤其是北京,一枝独秀,说明Go语言在北京的发展还是非常好的,学习和分享氛围也不错。

招聘公司

微信图片_20200109105457.jpg

该图表选择了一些招聘Go语言岗位多的公司进行分析,发现其中最多的是瓜子二手车,一个公司发布了19个Go语言开发的岗位,估计整个公司都快转Go语言了。

其次是滴滴公司,一共有13个在招聘Go语言的岗位,也是非常多了,看来滴滴对Go语言的推动力度很大。

除此之外,美团、百度、UCloud以及腾讯等公司都有3-5个Go语言的岗位在招聘,说明这些公司也陆陆续续开始用Go语言做一些适合的业务。

薪水分布

微信图片_20200109105503.jpg

薪水分布分析也过滤了分布比较少的区间,保留了主要的薪水区间。

从图表上看薪水开到15K-30K的Go语言岗位有71个,是岗位最多的薪水分布;其次是15K-25K的占51个;10K-20K的有49个。基本上一个Go语言开发都是上万。

此外,20K以上的Go语言岗位有89个,占总共450个岗位的近20%;25K以上的有31个,也占了总岗位的7%左右,比例也不算太低。

所以从这个看,Go语言做好了,20K以上也是非常轻松,最多可以开到50K。

经验要求

这个我保留了,没有分析,留给大家试试,看是1-3年的多,还是3-5年的多。

源代码

该代码只可用于学习研究之用,不可用于其他用途。

该爬取拉勾职位的Go语言爬虫,基于pholcus这个爬虫框架编写,是一个pholcus的爬取拉勾职位的规则库,大家使用的时候和正常的pholcus规则库是一样的,import导入引用即可。

关键字:数据采集 Go

不安分的 Go 强势入侵前端,后端难道要抢前端饭碗了?

有只黑白猫 发表了文章 • 0 个评论 • 679 次浏览 • 2020-01-08 16:35 • 来自相关话题

点击这里,查看Go写前端的具体操作步骤 ...查看全部

点击这里,查看Go写前端的具体操作步骤

image.png  

Go 语言写前端 Web 应用借助的是 WebAssembly 。

那什么是 WebAssembly 呢?它也叫 wasm ,是由 Google、Microsoft、Mozilla、Apple 等几家大公司合作发起的 WebAssembly 是一种新的字节码格式,主流浏览器都已经支持 WebAssembly。和 JS 需要解释执行不同,WebAssembly 字节码和底层机器码很相似可快速装载运行,因此性能相对于 JS 解释执行大大提升。也就是说 WebAssembly 并不是一门编程语言,而是一份字节码标准,需要用高级编程语言编译出字节码放到 WebAssembly 虚拟机中才能运行 。所以,理论上讲只要能编译成 WebAssembly 字节码的高级语言都可以写 Web 应用程序。

而 Go 的前端框架叫:Vugo 。它是一个 Go 语言开发库,可以很容易地使用 Go 语言编写 Web 用户界面。

image.png  

Vugu: 是一个用于 Go+WebAssembly 的现代 UI 库,受 Vue 和 React 等工具的启发,Vugu 是一个完全用 Go 编写的小型库,可以在现代浏览器中使用 WebAssembly 运行。

官网示例,go 写前端大概是这样的:

image.png  

关键字:Go语言 前端开发

Go 会接替 Java,成为下一个企业级编程语言吗?

有只黑白猫 发表了文章 • 2 个评论 • 568 次浏览 • 2020-01-07 14:33 • 来自相关话题

点击这里,查看 ...查看全部

点击这里,查看GO的优势、劣势等剩余重要内容

Go 的优势在于能够将简单的和经过验证的想法结合起来,同时避免了其他语言中出现的许多问题。本文概述了 Go 背后的一些设计原则和工程智慧,作者认为,Go 语言具备的所有这些优点,将共同推动其成为接替 Java 并主导下一代大型软件开发平台的最有力的编程语言候选。很多优秀的编程语言只是在个别领域比较强大,如果将所有因素都纳入考虑,没有其他语言能够像 Go 语言一样“全面开花”,在大型软件工程方面,尤为如此。

基于现实经验 Go 是由经验丰富的软件行业老手一手创建的,长期以来,他们对现有语言的各种缺点有过切身体会的痛苦经历。几十年前,Rob Pike 和 Ken Thompson 在 Unix、C 和 Unicode 的发明中起到了重要作用。Robert Griensemer 在为 JavaScript 和 Java 开发 V8 和 HotSpot 虚拟机之后,在编译器和垃圾收集方面拥有数十年的经验。有太多次,他们不得不等待 Google 规模的 C++/Java 代码库进行编译。于是,他们开始着手创建新的编程语言,将他们半个世纪以来的编写代码所学到的一切经验包含进去。

专注于大型工程 小型工程项目几乎可以用任何编程语言来成功构建。当成千上万的开发人员在数十年的持续时间压力下,在包含数千万行代码的大型代码库上进行协作时,就会发生真正令人痛苦的问题。这样会导致一些问题,如下:

  • 较长的编译时间导致中断开发。
  • 代码库由几个人 / 团队 / 部门 / 公司所拥有,混合了不同的编程风格。
  • 公司雇佣了数千名工程师、架构师、测试人员、运营专家、审计员、实习生等,他们需要了解代码库,但也具备广泛的编码经验。
  • 依赖于许多外部库或运行时,其中一些不再以原始形式存在。
  • 在代码库的生命周期中,每行代码平均被重写 10 次,被弄得千疮百痍,而且还会发生技术偏差。
  • 文档不完整。
    Go 注重减轻这些大型工程的难题,有时会以使小型工程变得更麻烦为代价,例如,代码中到处都需要几行额外的代码行。

注重可维护性 Go 强调尽可能多地将工作转给自动化的代码维护工具中。Go 工具链提供了最常用的功能,如格式化代码和导入、查找符号的定义和用法、简单的重构以及代码异味的识别。由于标准化的代码格式和单一的惯用方式,机器生成的代码更改看起来非常接近 Go 中人为生成的更改并使用类似的模式,从而允许人机之间更加无缝地协作。

保持简单明了

初级程序员为简单的问题创建简单的解决方案。高级程序员为复杂的问题创建复杂的解决方案。伟大的程序员找到复杂问题的简单解决方案。
——Charles Connell

让很多人惊讶的一点是,Go 居然不包含他们喜欢的其他语言的概念。Go 确实是一种非常小巧而简单的语言,只包含正交和经过验证的概念的最小选择。这鼓励开发人员用最少的认知开销来编写尽可能简单的代码,以便许多其他人可以理解并使用它。

使事情清晰明了 良好的代码总是显而易见的,避免了那些小聪明、难以理解的语言特性、诡异的控制流和兜圈子。

许多语言都致力提高编写代码的效率。然而,在其生命周期中,人们阅读代码的时间却远远超过最初编写代码所需的时间(100 倍)。例如,审查、理解、调试、更改、重构或重用代码。在查看代码时,往往只能看到并理解其中的一小部分,通常不会有完整的代码库概述。为了解释这一点,Go 将所有内容都明确出来。

错误处理就是一个例子。让异常在各个点中断代码并在调用链上冒泡会更容易。Go 需要手动处理和返回每个错误。这使得它可以准确地显示代码可以被中断的位置以及如何处理或包装错误。总的来说,这使得错误处理编写起来更加繁琐,但是也更容易理解。

简单易学 Go 是如此的小巧而简单,以至于人们可以在短短几天内就能研究通整个语言及其基本概念。根据我们的经验,培训用不了一个星期(相比于掌握其他语言需要几个月),初学者就能够理解 Go 专家编写的代码,并为之做出贡献。为了方便吸引更多的用户,Go 网站提供了所有必要的教程和深入研究的文章。这些教程在浏览器中运行,允许人们在将 Go 安装到本地计算机上之前就能够学习和使用 Go。

解决之道 Go 强调的是团队之间的合作,而不是个人的自我表达。

在 Go(和 Python)中,所有的语言特性都是相互正交和互补的,通常有一种方法可以做一些事情。如果你想让 10 个 Python 或 Go 程序员来解决同一个问题,你将会得到 10 个相对类似的解决方案。不同的程序员在彼此的代码库中感觉更自在。在查看其他人的代码时,国骂会更少,而且人们的工作可以更好地融合在一起,从而形成了一致的整体,人人都为之感到自豪,并乐于工作。这还避免了大型工程的问题,如:

关键字:GO  JAVA  编程语言

袋鼠存储 v1.4.1 来了:docker镜像,linux命令行安装,客户端...

fabsnail 发表了文章 • 1 个评论 • 484 次浏览 • 2020-01-07 12:20 • 来自相关话题

袋鼠存储是一款跨平台,跨网络管理数据,就近为用户提供服务的分布式服务。可通过官网文档 roostore.com/docs# 详细了解袋鼠存储自从发布以来,已 ...查看全部

袋鼠存储是一款跨平台,跨网络管理数据,就近为用户提供服务的分布式服务。可通过官网文档 roostore.com/docs# 详细了解

袋鼠存储自从发布以来,已得到大量用户的下载与使用反馈,在此感谢大家的支持与认可,我们继续努力改进和完善

现在 v1.4.1 版本来了,该版本提供docker镜像,linux命令行部署方式,并提供客户端等

kstore

1. 提供 docker 镜像
2. 提供 linux 一键安装 kstore 服务

客户端首发

1. 支持 windows,linux
2. 支持用户设置需要连接的 kstore 服务,默认使用本地服务
3. 提供下载管理列表:支持暂停,恢复和取消下载任务
4. 提供下载完成项管理列表:支持在系统资源管理器中打开和删除下载项
5. 支持直接下载目录
6. 支持设置默认下载存放目录

其他更新

1. 提供树莓派 4B 从开箱到部署运行袋鼠存储服务的实践教程
2. 重写边同步边下载逻辑,解决使用一些第三方工具下载得到的文件无效问题
3. 调整后台网络管理中不可显示子网管理员密码
4. 后台网络管理提供修改子网密码的入口
5. 后台管理页面样式微调,更轻快的视觉体验
6. 后台设备管理中调整添加同步帐号布局,显示更醒目
7. 用户头像菜单提供后台管理入口
8. 快速访问入口项提供图标
9. 登录界面显示正在登录动画
10. 刷新功能优化,本地不存在元数据时尝试等待网络同步返回并显示等待动画
11. 元数据同步逻辑优化,避免上传大批量小文件时出现频繁发起同步
12. 数据中心节点周期性主动发起同步
13. 上传对话框显示统计已上传的文件数,用户可自行重置该统计项
14. 调整上传过程中出错时的状态显示,点击可查看详细错误信息
15. 优化上传逻辑,解决当大批量上传文件时界面卡死问题
16. 修复通过拖放上传文件夹时每一层最多仅扫描 100 项问题
17. 修复上传过程中后端出现的:Access is denied 问题
18. 修复上传过程中若切换浏览目录导致上传目标位置改变问题
19. 修复上传时可能报错:无法找到文件问题
20. 修复上传时可能报错:invalid argument
21. 修复取消上传选中项时误取消所有上传任务问题
22. 修复通过拖放上传一次后,切换浏览目录再上传时,上传存放目录错误问题
23. 修复通过拖放上传时,若选择了多个文件仅上传选中的第一个文件问题
24. 修复新创建的子网,全新节点加入失败问题
25. 修复加载页在加载完毕后可能出现的不跳转问题

感兴趣的朋友,欢迎通过官网 roostore.com 下载使用

golang技术文章精选(2019)

hanyajun 发表了文章 • 0 个评论 • 552 次浏览 • 2020-01-07 10:06 • 来自相关话题

https://hanyajun.com/golang/go_article_2019/ ...查看全部

Go语言编程有哪些利与弊?编程时如何判断是否应该用Go?

有只黑白猫 发表了文章 • 2 个评论 • 520 次浏览 • 2020-01-06 13:38 • 来自相关话题

点击这里,查看 ...查看全部

点击这里,查看使用Go语言编程的弊端及何时使用Go语言编程等重要内容


我们喜欢 Go 语言的地方

近年来,Go 语言的使用量呈爆炸式增长。似乎每个初创公司都将它用于后端系统。开发人员认为它如此广受欢迎,背后的原因有很多。

Go 语言速度非常快 Go 语言是一门非常快速的编程语言。因为 Go 语言是编译成机器码的,因此,它的表现自然会优于那些解释性或具有虚拟运行时的编程语言。Go 程序的编译速度也非常快,并且生成的二进制文件非常小。我们的 API 在短短几秒钟内就编译完毕,生成的可执行文件区区只有 11.5MB 这么小。

易于掌握 与其他语言相比,Go 语言的语法很简单,很容易掌握。你完全可以把 Go 语言的大部分语法记在脑子里,这意味着你并不需要花很多时间来查找东西。Go 语言也非常干净易读。非 Go 语言的程序员,尤其是那些习惯于 C 风格语法的程序员,就可以阅读 Go 程序代码,并且能够理解发生什么事。

静态类型定义语言 Go 语言是一种强大的静态类型定义语言。有基本类型,如 int、byte 和 string。也有结构类型。与任何强类型语言一样,类型系统允许编译器帮助捕获整个类的错误。Go 语言还具有内置的列表和映射类型,而且它们也易于使用。

接口类型 Go 语言有接口类型,任何结构都可以简单地通过实现接口的方法来满足接口。这允许你解耦代码中的依赖项。然后,你可以在测试中模拟你的依赖项。通过使用接口,你可以编写更加模块化的可测试代码。Go 语言还具有头等函数,这使得开发人员以更实用的方式编写代码成为可能。

标准库 Go 语言有一个相当不错的标准库。它提供了方便的内置函数,用于处理基本类型。有些包可以让你轻松构建一个 Web 服务器、处理 I/O、使用加密技术以及操作原始字节。标准库提供的 JSON 序列化和反序列化非常简单。通过使用“tags”,你可以在 struct 字段旁边指定 JSON 字段名。

测试支持 测试支持内置在标准库中,不需要额外的依赖。如果你有个名为 thing.go 的文件,请在另一个名为 thing_test.go 的文件中编写测试,并运行“go test”。Go 就将快速执行这些测试。

静态分析工具 Go 语言的静态分析工具众多且强大。一种特别的工具是 gofmt,它根据 Go 的建议风格对代码进行格式化。这可以规范项目的许多意见,让团队奖经理集中在代码所做的工作上。我们对每个构建运行 gofmt、golint 和 vet,如果发现任何警告的话,则构建将会失败。

垃圾收集 在设计 Go 语言时,有意将内存管理设计得比 C 和 C++ 更容易。动态分配的对象是垃圾收集。Go 语言使指针的使用更加安全,因为它不允许指针运算。还提供了使用值类型的选项。

更容易的并发模型 虽然并发编程从来就不是一件易事,但 Go 语言在并发编程要比其他语言更容易。创建一个名为“goroutine”的轻量级线程,并通过“channel”与它进行通信几乎是非常简单的事情,至于更为复杂的模型,也是有可能能够实现的。

我们不喜欢 Go 语言的地方

正如我们前面讨论过的,Go 语言确实是一门优秀的语言。它有一个干净的语法,执行速度也很快速。它还有很多优点。但是,编程语言的全部并不仅仅是指它的语法。下面是我们遇到的一些问题。


关键字:GO语言   编程语言 

2020年Go语言那些不得不看的最新面试题

有只黑白猫 发表了文章 • 0 个评论 • 595 次浏览 • 2020-01-06 13:31 • 来自相关话题

点击这里,查看 ...查看全部

点击这里,查看剩余5道2020年最新面试题及其解析

1、编译执行下面代码会出现什么?

package main
var(
size :=1024
max_size = size*2
)
func main() {
println(size,max_size)
}

解析 考点:变量简短模式 变量简短模式限制: - 定义变量同时显式初始化 - 不能提供数据类型 - 只能在函数内部使用

结果:

syntax error: unexpected :=
2、下面函数有什么问题?
package main
const cl = 100

var bl = 123

func main() {
println(&bl,bl)
println(&cl,cl)
}

解析 考点:常量 常量不同于变量的在运行期分配内存,常量通常会被编译器在预处理阶段直接展开,作为指令数据使用,

cannot take the address of cl

3、编译执行下面代码会出现什么?

package main

func main() {

for i:=0;i<10 ;i++ {
loop:
println(i)
}
goto loop
}

解析 考点:goto goto不能跳转到其他函数或者内层代码

goto loop jumps into block starting at

4、编译执行下面代码会出现什么?

package main
import "fmt"

func main() {
type MyInt1 int
type MyInt2 = int
var i int =9
var i1 MyInt1 = i
var i2 MyInt2 = i
fmt.Println(i1,i2)
}

解析 考点:Go 1.9 新特性 Type Alias 基于一个类型创建一个新类型,称之为defintion;基于一个类型创建一个别名,称之为alias。 MyInt1为称之为defintion,虽然底层类型为int类型,但是不能直接赋值,需要强转; MyInt2称之为alias,可以直接赋值。

结果:

cannot use i (type int) as type MyInt1 in assignment

5、编译执行下面代码会出现什么?

package main
import "fmt"

type User struct {
}
type MyUser1 User
type MyUser2 = User
func (i MyUser1) m1(){
fmt.Println("MyUser1.m1")
}
func (i User) m2(){
fmt.Println("User.m2")
}

func main() {
var i1 MyUser1
var i2 MyUser2
i1.m1()
i2.m2()
}

解析 考点:Go 1.9 新特性 Type Alias 因为MyUser2完全等价于User,所以具有其所有的方法,并且其中一个新增了方法,另外一个也会有。 但是

i1.m2()

是不能执行的,因为MyUser1没有定义该方法。 结果:

MyUser1.m1
User.m2

关键字:Go语言  面试  

在 go websocket server 与 javascript websocket client 交互中使用 flatbuffers

tsingson 发表了文章 • 0 个评论 • 543 次浏览 • 2020-01-04 00:36 • 来自相关话题

> 代码在 [https://github.com/tsingson/fastws-example](https://github.com/ ...查看全部



> 代码在 [https://github.com/tsingson/fastws-example](https://github.com/tsingson/fastws-example)


## 0. 简要说明
为某个开源项目增加 websocket 对接, 写了这个示例

代码中 javascript 对 flatbuffers 的序列化/反序列化, 查了一天资料, 嗯哼, 最终完成了.
看代码吧.........

-----------
### 0.1 关于序列化/反序列化
序列化 serialized / 反序列化 un-serialized , 一般是指对像转成二进制序列( 或叫二进制数组), 以及逆向从二进制转成对像的过程, 一般用在几个地方
1. 网元之间传输. 比如 RESTfull 是在 HTTP 协议( HTML over TCP ) 上进行交互时使用 JSON 数据格式进行序列化与反序列化; 比如 gRPC 默认采用 protobuffers 在 HTTP2 传输上进行数据序列化与反序列化;
2. 对象数据持久化存储到文件系统, 以及从文件系统读取到对象时;
3. 异构开发SDK或API之间交互或共享数据, 比如 go语言调用底层 c++ 库........

### 0.2 关于 flatbuffers
flatbuffers 是 google 员工在开发游戏过程中, 仿 protobuffers 写的一个高性能序列化/反序列化库, 通过 IDL (接口描述语言) 定义, 通过 flatc 编译为多种语言的接口对象序列化/反序列化的强类型库, 支持 c++ / c / java / python / rust / js / typescript / go / swift.........

fastbuffers 的介绍, 参见 [于德志](https://halfrost.com/) 的文章 [https://halfrost.com/flatbuffers_schema/](https://halfrost.com/flatbuffers_schema/), 几篇文章写得很细致,精确,完整
> **PS: [于德志](https://halfrost.com/) 的技术专题介绍文章,语言简练易懂, 配图简单明了,非常值得一读**
>
>
> 说起来, 我的英文阅读能力还可以, 但不得不说, 访问 [于德志](https://halfrost.com/) 的 [https://halfrost.com/tag/protocol/ 协议相关专题文章](https://halfrost.com/tag/protocol/) 还是很愉悦轻松. 谢谢了!



flatbuffers 的特点, 个人见解:

1. flatbuffers 的序列化, 慢于 protobuffers ( 约是 protobuffers 的两倍耗时) , 与 JSON 相仿, 甚至有时慢于 json
2. flatbuffers 的反序列化, 约10倍快于 protobuffers, 当然也就快于 JSON 了
3. flatbuffers 在反序列化时, 是内在零拷贝, 序列化后的数据与内存中是一致的, 这让 flatbuffers 序列化后的二进制数据直接导入内存, 以及从内存中读取时都非常快

所以, 在一次序列化, 而多次反序列化的情况下, 以及对反序列化要求速度非常快的情况, 可以考虑选择 flatbuffers , 想想 google 员工为游戏而开发 flatbuffers 这一典型场景吧

### 0.3 我在哪里使用( 或计划使用 ) flatbuffers ?
在以下场景中, 我使用了( 或正在计划使用) flatbuffers:

1. Sub/Pub 订阅/发布的消息系统. 在某些 Sub/Pub 场景中, Pub 时序列化消息对象, 尤其是 flatbuffers 中的 union , 挺好用. ------------- 而在 Sub 订阅消费端, 尤其多端消费, 高效的反序列化, 可以减少最多达1/4, 平均1/5 左右时延 (注: 仅是个人应用场景的经验值, 供参考)
2. 内存缓存( 包括 session 会话数据) , 某些应用中的内存缓存需要持久化, 这些内存缓存通过并发保存到多个文件后, 在应用重启时从文件中重建缓存, 非常快
3. IM 即时通讯, 以及某些情况下的 gRPC, 这个与第一条类似. 参见我以前的文章 [GOIM的架构与定制](https://juejin.im/post/5cbb9e68e51d456e51614aab)------ 事实上, 这一篇文章, 正是为定制开发的 IM 而准备. --------- 至于 gRPC , 是的, gRPC 默认的 ptotobuffers 可以用 flatbuffers 更换, 我在几个商用项目中使用, 某商用项目中的 gRPC + flatbuffers 已经上线运行一年了.

### 0.4 flatbuffers 的重大改进

之前, flatbuffers 在序列化时代码很让人着急, 但2019年12月的一个改进, 让 flatbuffers 序列化时代码简化不少

```
flatc --gen-object-api ./*.fbs
```

以上参数的添加, 让 flatbuffers 序列化简单如下:

```
// --------------- 这是 fbs 文件中的 IDL
table LoginRequest{
msgID:int=1;
username:string;
password:string;
}

// -------------- 这是 flatc 编译后的 go 代码
type LoginRequestT struct {
MsgID int32
Username string
Password string
}

func LoginRequestPack(builder *flatbuffers.Builder, t *LoginRequestT) flatbuffers.UOffsetT {
if t == nil {
return 0
}
usernameOffset := builder.CreateString(t.Username)
passwordOffset := builder.CreateString(t.Password)
LoginRequestStart(builder)
LoginRequestAddMsgID(builder, t.MsgID)
LoginRequestAddUsername(builder, usernameOffset)
LoginRequestAddPassword(builder, passwordOffset)
return LoginRequestEnd(builder)
}

// ----------- 这是我做的简单封装
func (a *LoginRequestT) Byte() []byte {
b := flatbuffers.NewBuilder(0)
b.Finish(LoginRequestPack(b, a))
return b.FinishedBytes()
}


//---------------- 这里是序列化
l := &LoginRequestT{
MsgID: 1,
Username: "1",
Password: "1",
}

b := l.Byte() // ------------- 变量 b 是序列化后的二进制数组


```




## 1. 使用代码库

示例代码使用了以下开源库
* [fasthttp](http://github.com/valyala/fasthttp)
* [fasthttp router](https://github.com/fasthttp/router)
* [fastws ](https://github.com/fasthttp/fastws) ---- fasthttp 实现的 websocket 库
* [flatbuffers](https://github.com/google/flatbuffers) ---- flatbuffers 高效反序列化通用库, 用在 go语言/javascript
* [websockets/ws](https://github.com/websockets/ws) ---- javascript websocket 通用库

## 1. flatbuffers IDL 示例
xone.fbs 示例来自 [https://www.cnblogs.com/sevenstar/p/FlatBuffer.html](https://www.cnblogs.com/sevenstar/p/FlatBuffer.html), 感谢!!

```
namespace xone.genflat;

table LoginRequest{
msgID:int=1;
username:string;
password:string;
}

table LoginResponse{
msgID:int=2;
uid:string;
}

//root_type非必须。

//root_type LoginRequest;
//root_type LoginRespons
```

## 2. flatc 编译代码

生成 javascript

```
flatc -s --gen-mutable ./*.fbs
```



生成 golang

```
flatc --go --gen-object-api --gen-all --gen-compare --raw-binary ./*.fbs
```

## 3. 主要代码说明

```
./cmd/wsserver/main.go ----- websocket server
./cmd/wsclient/main.go ----- websocket client
./ws/... ------------------- websocket go code for websocket handler and websocket client
./jsclient/ws.js ---------- javascript client code , please check-out package.json for depends
```




## 4. javascript 序列化/反序列化

**请注意代码注释中的--------- 特别注意这一行**

```
// ------------ ./jsclient/index.js

const flatbuffers = require('./flatbuffers').flatbuffers;
const xone = require('./xone_generated').xone; //Generated by `flatc`.

//-------------------------------------------
// serialized
//-------------------------------------------
let b = new flatbuffers.Builder(1);
let username = b.createString("zlssssssssssssh");
let password = b.createString("xxxxxxxxxxxxxxxxxxx");
xone.genflat.LoginRequest.startLoginRequest(b);
xone.genflat.LoginRequest.addUsername(b, username);
xone.genflat.LoginRequest.addPassword(b, password);
xone.genflat.LoginRequest.addMsgID(b, 5);
let req = xone.genflat.LoginRequest.endLoginRequest(b);
b.finish(req); //创建结束时记得调用这个finish方法。


let uint8Array = b.asUint8Array(); // ------------- 特别注意这一行

console.log(uint8Array);
// console.log(b.dataBuffer() );
//-------------------------------------------
// un-serialized
//-------------------------------------------
let bb = new flatbuffers.ByteBuffer(uint8Array); //-------------- 特别注意这一行
let lgg = xone.genflat.LoginRequest.getRootAsLoginRequest(bb);


console.log("username: ", lgg.username());
console.log("password", lgg.password());
console.log("msgID: ", lgg.msgID());

```



## 5. golang 中对 flatbuffers 的序列化/反序列化

```

// ------ ./apis/genflat/model.go

func (a *LoginRequestT) Byte() []byte {
b := flatbuffers.NewBuilder(0)
b.Finish(LoginRequestPack(b, a))
return b.FinishedBytes()
}

func ByteLoginRequestT(b []byte) *LoginRequestT {
return GetRootAsLoginRequest(b, 0).UnPack()
}


// ------- ./apis/genflat/model_test.go

func TestLoginRequestT_Byte(t *testing.T) {
as := assert.New(t)
// serialized
l := &LoginRequestT{
MsgID: 1,
Username: "1",
Password: "1",
}

b := l.Byte()

// un-serialized
c := ByteLoginRequestT(b)
if l.MsgID > 0 {
fmt.Println(" id > ", c.MsgID, " u > ", c.Username, " pw > ", c.Password)
}

as.Equal(l.Password, c.Password)

}

```

## 6. websocket 代码
```

ws.onmessage = (event) => {
//-------------------------------------------------------------------
// read from websocket and un-serialized via flatbuffers
//--------------------------------------------------------------------
let aa = str2ab(event.data);
let bb = new flatbuffers.ByteBuffer(aa);
let lgg = xone.genflat.LoginRequest.getRootAsLoginRequest(bb);
let pw = lgg.password();

if (typeof pw === 'string') {
console.log("----------------------------------------------");

console.log("username: ", lgg.username());
console.log("password", lgg.password());
console.log("msgID: ", lgg.msgID());
} else {
console.log("=================================");
console.log(event.data);
}


// console.log(`Roundtrip time: ${Date.now() }` , ab2str(d ));

setTimeout(function timeout() {
//-------------------------------------------------------------------
// serialized via flatbuffers and send to websocket
//--------------------------------------------------------------------
let b = new flatbuffers.Builder(1);
let username = b.createString("zlssssssssssssh");
let password = b.createString("xxxxxxxxxxxxxxxxxxx");
xone.genflat.LoginRequest.startLoginRequest(b);
xone.genflat.LoginRequest.addUsername(b, username);
xone.genflat.LoginRequest.addPassword(b, password);
xone.genflat.LoginRequest.addMsgID(b, 5);
let req = xone.genflat.LoginRequest.endLoginRequest(b);
b.finish(req); //创建结束时记得调用这个finish方法。


let uint8Array = b.asUint8Array();

ws.send(uint8Array);
}, 500);
};

function str2ab(str) {
let array = new Uint8Array(str.length);
for (let i = 0; i < str.length; i++) {
array[i] = str.charCodeAt(i);
}
return array
}

```



## 6. 参考

* [https://github.com/google/flatbuffers/issues/3781](https://github.com/google/flatbuffers/issues/3781)



## 7. 其他

macOS 下从源码编译 flatc
```
git clone https://github.com/google/flatbuffers

cd github.com/google/flatbuffers

cmake -G "Xcode" -DCMAKE_BUILD_TYPE=Release

cmake --build . --target install

```

Go语言错题及答案整理

回复

有只黑白猫 发起了问题 • 1 人关注 • 0 个回复 • 138 次浏览 • 2020-01-03 14:55 • 来自相关话题

Go语言最新面试题及其解析(一)

有只黑白猫 发表了文章 • 0 个评论 • 628 次浏览 • 2020-01-02 15:22 • 来自相关话题

点击这里,查看剩余 ...查看全部

点击这里,查看剩余3道最新面试题及其解析


简介: 了解最新的Go语言面试题型,让面试不再是难事。


1.select是随机的还是顺序的

select会随机选择一个可用通道做收发操作

2.Go语言局部变量分配在栈还是堆?

Go语言编译器会自动决定把一个变量放在栈还是放在堆,编译器会做逃逸分析,当发现变量的作用域没有跑出函数范围,就可以在栈上,反之则必须分配在堆。

查看资料

3.简述一下你对Go垃圾回收机制的理解?

v1.1 STW
v1.3 Mark STW, Sweep 并行
v1.5 三色标记法
v1.8 hybrid write barrier(混合写屏障:优化STW)

Golang垃圾回收剖析

关键字:存储  JSON  监控  Java  编译器  测试技术  Go  API  调度  数据格式

Go语言出现后,Java还是最佳选择吗?

有只黑白猫 发表了文章 • 1 个评论 • 610 次浏览 • 2020-01-02 15:01 • 来自相关话题

点击这里,查看异步与协程的关系,手工异 ...查看全部


点击这里,查看异步与协程的关系,手工异步/Wisp性能比较,适应的Workload等更多重要内容

简介: 阿里妹导读:随着大量新生的异步框架和支持协程的语言(如Go)的出现,在很多场景下操作系统的线程调度成为了性能的瓶颈,Java也因此被质疑是否不再适应最新的云场景了。4年前,阿里JVM团队开始自研Wisp2,将Go语言的协程能力带入到Java世界。

image  
Java平台一直以生态的繁荣著称,大量的类库、框架帮助开发者们快速搭建应用。而其中大部分Java框架类库都是基于线程池以及阻塞机制来服务并发的,主要原因包括:

Java语言在核心类库中提供了强大的并发能力,多线程应用可以获得不俗的性能;
Java EE的一些标准都是线程级阻塞的(比如JDBC);
基于阻塞模式可以快速地开发应用。
但如今,大量新生的异步框架和支持协程的语言(如Go)的出现,在很多场景下操作系统的线程调度成为了性能的瓶颈。Java也因此被质疑是否不再适应最新的云场景了。

4年前,阿里开始自研Wisp2。它主要是用在IO密集的服务器场景,大部分公司的在线服务都是这样的场景 (离线应用都是偏向于计算,则不适用)。它在功能属性上对标Goroutine的Java协程,在产品形态、性能、稳定性上都达到了一个比较理想的情况。到现在,已经有上百个应用,数万个容器上线了Wisp1/2。Wisp协程完全兼容多线程阻塞的代码写法,仅需增加JVM参数来开启协程,阿里巴巴的核心电商应用已经在协程模型上经过两个双十一的考验,既享受到了Java的丰富生态,又获得了异步程序的性能。

Wisp2主打的是性能和对现有代码的兼容性,简而言之,现有的基于多线程的IO密集的Java应用只需要加上Wisp2的JVM参数就可以获得异步的性能提升。

作为例子,以下是消息中间件代理(简称mq)和drds只添加参数不改代码的压测比较:

image  

可以看到上下文切换以及sys CPU显著降低,RT减少、QPS分别提升11.45%,18.13%。

Quick Start
由于Wisp2完全兼容现有的Java代码,因此使用起来十分简单,有多简单?

如果你的应用是“标准”的在线应用(使用/home/admin/$APP_NAME/setenv.sh配置参数),那么在admin用户下输入如下命令就可以开启Wisp2了:

curl https://gosling.alibaba-inc.com/sh/enable-wisp2.sh | sh

否则需要手动升级JDK和Java参数:

ajdk 8.7.12_fp2 rpm

sudo yum install ajdk -b current # 也可以通过yum安装最新jdk
java -XX:+UseWisp2 .... # 使用Wisp参数启动Java应用

然后就可以通过jstack验证协程确实被开启了。

Carrier线程是调度协程的线程,下方的- Coroutine [...]表示一个协程,active表示协程被调度的次数,steal表示被work stealing的次数,preempt表示时间片抢占次数。

image  

下图是DRDS在ecs上压测时的top -H,可以看出来应用的数百个线程被8个Carrier线程托管,均匀地跑在CPU核数个线程上面。下方一些名为java的线程是gc线程。

image  

过多线程的开销
误区1: 进内核引发上下文切换

我们看一段测试程序:


pipe(a);while (1) { write(a[1], a, 1); read(a[0], a, 1); n += 2;}


image  
执行这段程序时上下文切换非常低,实际上上面的IO系统调用都是不会阻塞的,因此内核不需要挂起线程,也不需要切换上下文,实际发生的是用户/内核态的模式切换。

上面的程序在神龙服务器测得每个pipe操作耗时约334ns,速度很快。

误区2: 上下文切换的开销很大

本质上来说无论是用户态还是内核态的上下文切换都是很轻量的,甚至有一些硬件指令来支持,比如pusha可以帮助我们保存通用寄存器。同一个进程的线程共享页表,因此上下文切换的开销一般只有:

保存各种寄存器
切换sp(call指令会自动将pc压栈)
可以在数十条指令内完成。

开销

既然近内核以及上下文切换都不慢,那么多线程的开销究竟在哪?

我们不妨看一个阻塞的系统调用futex的热点分布:

image  

可以看到上面的热点中有大量涉及调度的开销。我们来看过程:

调用系统调用(可能需要阻塞);
系统调用确实需要阻塞,kernel需要决定下一个被执行的线程(调度);
执行上下切换。
因此,上面2个误区与多线程的开销都有一定因果关系,但是真正的开销来源于线程阻塞唤醒调度。

综上,希望通过线程模型来提升web server性能的原则是:

活跃线程数约等于CPU个数
每个线程不太需要阻塞
文章后续将紧紧围绕这两个主题。

为了满足上述两个条件,使用eventloop+异步callback的方式是一个极佳的选择。

关键词:Dubbo Java 应用服务中间件 Go 调度

我是如何从Java转型为Go区块链工程师

Bytom 发表了文章 • 0 个评论 • 957 次浏览 • 2020-01-02 11:39 • 来自相关话题

  我是如何从Java转型为Go区块链工程师 ...查看全部

  

我是如何从Java转型为Go区块链工程师

本文来自于一个比原链核心开发的陈述

前言

本人在加入比原链之前一直是做Java开发的,当初看到Go还有点犹豫,还怕过不了面试,结果是否掌握一门语言的考量确实没那么高,我顺利入职比原链,并在半个月内很快掌握Go并能够进行核心项目的开发。 Java语言在较大的成熟项目上具有优势,但是在区块链开发中确实会有很多短处,比如在协程处理上,还有Java语言本身不够灵活等等,当然选择使用Go主要是因为其在区块链的流行程度。

区块链的流行语言

在区块链公链的开发圈子里,我们找到了一些流行的编程语言,有C++、Golang、Python和最近新起的Rust等等。

稍微对比较有名的项目采用的编程语言做个统计,如下图:

  

老一代的公链,比如Bitcoin,Litcoin一般使用C/C++较多(我们看看那个时间,当时Go还没起来呢),新一代的公链比如以太坊,联盟链翘楚超级账本,开始较多使用Go语言,当然我们看到Rust的发展势头也很猛,近两年的很多公链比如波卡,Grin都开始采用Rust语言开发了。

Go语言的优势

部署简单

Go 编译生成的是一个静态可执行文件,除了 glibc 外没有其他外部依赖。这让部署变得异常方便:目标机器上只需要一个基础的系统和必要的管理、监控工具,完全不需要操心应用所需的各种包、库的依赖关系,大大减轻了维护的负担。可直接编译成机器码,不依赖其他库,glibc的版本有一定要求,部署就是扔一个文件上去就完成了。

性能优秀

虽然不如 C 和 Java,但通常比原生 Python 应用还是高一个数量级的,适合编写一些瓶颈业务。内存占用也非常省。

并发性&通道

Goroutine 和 channel 使得编写高并发的服务端软件变得相当容易,很多情况下完全不需要考虑锁机制以及由此带来的各种问题。单个 Go 应用也能有效的利用多个 CPU 核,并行执行的性能好。

良好的语言设计

Go 非常简单,且易于学习。从学术的角度讲 Go 语言其实非常平庸,不支持许多高级的语言特性;但从工程的角度讲,Go 的设计是非常优秀的:规范足够简单灵活。正是由于 Go 的简单性,任何的 Python、Elixir、C++、Scala 或者 Java 开发者皆可在一月内组建成一个高效的 Go 团队。

标准库&工具

Go目前已经内置了大量的库,特别是网络库非常强大。更重要的是 Go 自带完善的工具链,大大提高了团队协作的一致性。比如 gofmt 自动排版 Go 代码,很大程度上杜绝了不同人写的代码排版风格不一致的问题。把编辑器配置成在编辑存档的时候自动运行 gofmt,这样在编写代码的时候可以随意摆放位置,存档的时候自动变成正确排版的代码。此外还有 gofix, govet 等非常有用的工具。

团队牛逼

Go语言后面的支持者是Google,语言足够在各种场景下得到检验,同时创始人还是C语言之父,对后续的发展和创新可期。

Go成功的项目

Go语言在云时代得到了比较广泛的应用,特别是Docker和K8s这样的杀手级产品的出现让Go语言在工程界占有一席之地 除此之外Go语言还有非常多的成功运行中的软件: nsq:bitly开源的消息队列系统,性能非常高,目前他们每天处理数十亿条的消息 packer:用来生成不同平台的镜像文件,例如VM、vbox、AWS等,作者是vagrant的作者 skynet:分布式调度框架 Doozer:分布式同步工具,类似ZooKeeper Heka:mazila开源的日志处理系统 cbfs:couchbase开源的分布式文件系统 tsuru:开源的PAAS平台,和SAE实现的功能一模一样 groupcache:memcahe作者写的用于Google下载系统的缓存系统 god:类似redis的缓存系统,但是支持分布式和扩展性 gor:网络流量抓包和重放工具


生态卡位和隐性标准

除了打铁还需自身硬之外,还有些机遇和运势,让区块链选择的了Go语言。我们来看区块链2.0以来最成功的公链和联盟链代表,以太坊和超级账本Fabric,无一例外都选择使用Go作为开发语言(虽然以太坊其实也有其他语言的客户端版本,但进入到Homestead阶段以后,Go客户端占据了主导地位),这两大超级区块链的影响力可不是一般项目可以比拟的,不仅在生态中占据了大的坑位,事实上还隐性的制定了区块链的标准,不论是公链中的智能合约,还是联盟链的技术,都绕不开以太坊和Fabric,那么对于一家想要做区块链技术选型的公司来说,最快捷的实现是什么?自然是直接照搬这两个项目的创新,再捷径一点就是直接拿开源代码改,那么自然Go语言就成为后来者的首选,换种语言重新实现一遍难度也不小,而且如果选择一些创新但不是非常成熟的语言还会缺失一些特定库的支持从而导致项目无法开展。

很多人对以太坊的影响力毋庸置疑,但实际上Fabric在企业区块链部署上的影响力更不容小觑:

  

图表来源《2019年全球企业区块链基准研究报告》

Hyperledger Fabric是已部署的企业区块链网络中使用最多的协议框架,超级账本Hyperledger(其中Fabric作为旗舰协议)是集成商和软件开发平台最常支持的协议框架,比例达到了53%。 而在所有的区块链技术书籍里面,有关超级账本的书籍是卖的最为火爆这个事实也是侧面印证了超级账本Hyperledger的影响力。

比原链在Go语言中的实践

在选型编程语言的过程中,考量了C,C++, Java,但C/C++大项目维护难度大,而Java又略显笨重,此时Go语言已经在区块链项目上大放异彩,也逐渐形成技术和人才的一个头部效应,那么顺应潮流进行技术选型自然也会减少初始比原链项目遇到的阻力,当然在逐渐开发过程中,我们也感受到了选用Go语言带来的便利和优势。

Go在区块链上的一个Case

从技术上来说,区块链节点是需要多模块异步协同工作的,所以Go语言并发性和通道就显得非常有优势,我们看下面交易验证的例子:

func ValidateTxs(txs []*bc.Tx, block *bc.Block) []*ValidateTxResult {
txSize := len(txs)
//init the goroutine validate worker
var wg sync.WaitGroup
workCh := make(chan *validateTxWork, txSize)
resultCh := make(chan *ValidateTxResult, txSize)
closeCh := make(chan struct{})
for i := 0; i <= validateWorkerNum && i < txSize; i++ {
wg.Add(1)
go validateTxWorker(workCh, resultCh, closeCh, &wg)
}

//sent the works
for i, tx := range txs {
workCh <- &validateTxWork{i: i, tx: tx, block: block}
}

//collect validate results
results := make([]*ValidateTxResult, txSize)
for i := 0; i < txSize; i++ {
result := <-resultCh
results[result.i] = result
}

close(closeCh)
wg.Wait()
close(workCh)
close(resultCh)
return results
}

我们使用Routine+Ch+WaitGroup在30行代码之内,就可以构建一个并发的验证交易的功能,在高配置的服务器的情况下,可以跑出10万以上的TPS。

轻松变成Go语言大师

我当初进入比原之前也没有做过Go语言开发,但都能够很快上手,基本在半个月内能够参与核心代码的开发和维护了(对于从C/C++/Java有经验的开发者尤其快速),这就是语言简单对团队构建带来的好处。

统一的协作

从协作上来说,通过gofmt 自动排版 Go 代码,能够让核心团队成员甚至社区开发者提交的代码风格的差异性降到最小,提升项目的整体质量和可维护性。

小结

Go语言本身的特质和优势为其做好了铺垫,而以太坊和超级账本两个超级区块链项目的加持也让Go语言成为了很多区块链项目的首选,比原链选用Go语言也充分体会到了其开发区块链底层的优势,但是无需落入语言之争的陷阱,讲求实用主义才是做工程应有之义,比原链核心项目是用Go语言完成,但是周边的很多子项目也有用Java,Python或者JavaScript实现,毕竟生态的多样性才是一个项目长久的根本。

浅谈Go类型转换之间的那些事

阿伟 发表了文章 • 0 个评论 • 604 次浏览 • 2020-01-02 09:26 • 来自相关话题

试着答一答这些问题s[i]和(for _,v range)的v的区别是什么var s ...查看全部

试着答一答这些问题

s[i]和(for _,v range)的v的区别是什么
var s string = "AB"
fmt.Println(reflect.TypeOf(s[0]))
for _, v := range s {
fmt.Println(reflect.TypeOf(v))
}
a.(),和 a(b) 的区别是什么?
var v interface{} = 1var s uint8 = 1

temp1 := int(s)
temp2 := v.(int)

fmt.Println(temp1,temp2)

Go的类型系统了解

Go的类型

Go语言是一门静态编译型语言,是一门强类型语言,Go语言中类型分为两种:命名类型(已定义类型)和未命名类型(组合类型),我举例说一下

  1. 命名类型(已定义类型)
uint8(byte) uint16 uint32 uint64 int int8 int16 int32(rune) int64 bool stringfloat32 float64 complex64 complex128

上面举例类型归为三大类:,数值类型,字符串类型, 布尔值类型,我们使用type定义的任何类型也被称为命名类型,如下

//也是命名类型type MyBool bool 
  1. 未命名类型 (组合类型)
slice map chan function interface struct pointer

上面举例的类型有容器类型,函数类型,指针类型,结构体类型,通道类型,接口类型

自定义类型和底层类型

Go允许通过type关键字定义一个类型

Go的每一个类型都一个底层类型,类型的底层类型有如下规律

  1. 每一个命名类型的底层类型都是自己
  2. 每一个组合类型的底层类型都是自己
  3. 在一个类型的声明中,新声明的类型和原类型的底层类型是共享的

如下代码,请问这段代码能够编译成功吗?为什么?首先这段代码是编译失败的,i的类型是MyInt,j的类型是int,虽说她们的底层类型都是int,但不能相互赋值,也就说明命名类型间是不能相互赋值的,即便是低限制往高限制赋值,比如 int32 赋给 int64也是编译失败的

type MyInt intfunc CustomType() {
var i MyInt = 2
var j int = 1
j = i
i = j
fmt.Println(i == j)
}

下面这段代码会打印这两个变量的基本类型和底层类型,

//输出MyInt int
fmt.Println(reflect.TypeOf(i), reflect.TypeOf(j))
//输出int int
fmt.Println(reflect.TypeOf(i).Kind(), reflect.TypeOf(j).Kind())

我们再来看一个Demo,下面这段代码编译会报错吗,如果把int32改成int64呢?答案是编译报错,改成int64也会编译报错,只有j和int32同时改成i和int64,才会编译成功。因为这时m和n的底层类型是完全相同的。

type MyM struct {
i int64
}
type MyN struct {
j int32
}
func TestStruct() {
n := MyN{j: 10}
var m MyM
m = MyM(n)
fmt.Println(n,m)
}
如何追踪朔源一个类型的的底层类型

如下代码,说说这些类型的底层类型是什么?

type MyInt inttype I MyInt
type Ints []inttype MyInts []MyInt
type M map[string]stringtype CustomM M

MyInt的底层类型是int

I的底层类型时int

Ints的底层类型是[]int

MyInts的底层类型是slice

M的底层类是map

CustomM的底层类是map

规律就是直到找到的一个内置类型(Go内置的类型)或者未命名类型(组合类型)结束,这个类型就是当前类型的底层类型

怎么通过代码获取一个类型的底层类型呢?通过下面代码获取

reflect.TypeOf(variable).Kind()
类型别名

什么是类型别名呢?Go中有两个类型别名 byte,对应的真实类型是uint8,rune,对应的真实类型是int32,我们可以源代码中这两个的定义如下

// byte is an alias for uint8 and is equivalent to uint8 in all ways. It is// used, by convention, to distinguish byte values from 8-bit unsigned// integer values.type byte = uint8

// rune is an alias for int32 and is equivalent to int32 in all ways. It is// used, by convention, to distinguish character values from integer values.type rune = int32

从这个就能就能解决最开始的第一个问题,s[index]取得是字符串转换成字节后的某一个字节,而range指的是循环字符串s的每一个字符(range会隐式的unicode解码), 但字符区分字母和汉字,一个字母占用一个字节,一个汉字可不是了,看如下代码,你可以获取byte和rune的底层类型

var r rune = 'c'var b byte = 1
fmt.Println(reflect.TypeOf(r).Kind()) //int32
fmt.Println(reflect.TypeOf(b).Kind()) //uint8

如何定义一个类型别名呢?其实很简单,知道怎么定义一个类型,那么定义一个类型别名就很简单了,参考上面的byte和rune,如下我们为int64定义一个别名(从Go1.9开始支持),类型别名是可以被声明在函数体内的

//相比定义一个类型多了一个=号type alaisInt64 = int64
类型转换和断言

类型转换是用来在类型不同但相互兼容的类型之间的相互转换的方式,如果不兼容,则无法相互转换,编译会报错,通常写法是 a(b),把b转换成a

类型断言是在接口之间进行,本质也是类型转换,写法是a.(b),含义是把a转换成b

如下代码,做一些错误的和正确的示范

//这个转换时类型不同,也不兼容,所以编译报错
s := "ab"
i := int(s)

//这个转换类型不同,但兼容,所以OKvar j int8 = 1
m := int(j)

//这个转换是失败的,系统会检测到类型不匹配,直接panicvar k interface{} = "s"
l := k.(int)
//但我们可以通过一个参数来判断,只有f为true时,才会转换成功
l,f := k.(int)
//这个转换是成功的
p,f := k.(string)

类型转换的实践,勤加练习才能理解

数字类型之间转换

从低位转高位没有什么问题,从高位转低位时(会丢失精度),int64转int8,这个转换的过程如下:

128的二进制:.........00000000_10000000

因为是从int64转int8,所以截取128的后八位 :10000000

此时最高位是1,表示这是一个负数,此时结果是就是:-128

//这个转换没有任何问题,都OKvar i int8 = 123var j int16 = int16(i)
//这个转换会丢失精度,从高位转低位var m int64 = 128var n int8 = int8(m) //n的结果是-128,因为int8能表达的最大值是127,最小值是-128,
字符串,字节,数字,字符互相转换
var s1,s2 string = "AbcD","1234"//转字节
bs1 := []byte(s1); bs2 := []byte(s2)

//字节数组转字符串
s11 := string(bs1); s22 := string(bs2)
//单个字节转字符串
ss := string(bs1[0])
fmt.Println(s11, s22, ss)

//s2转数字 ,err 表示是否能转换成功,比如s1就会转换失败
i, err := strconv.Atoi(s2)
//数字转字符串
s := strconv.Itoa(i)

//字符串转字符数组
runes := []rune(s1)

//字符数组转字符串
ss1 := string(runes)
//单个字符转字符串
ss2 := strconv.QuoteRune(runes[0])

//字符转字节
bss := make([]byte, 0)
bss = strconv.AppendQuoteRune(bss, runes[0])
fmt.Println(err, s, ss1, ss2, runes[0], bss, string(bss))
//除开rune和byte底层的类型的区别,在使用上,//rune能处理一切的字符,而byte仅仅局限在ascii

//整形转字节
x := int32(68)
bytesBuffer := bytes.NewBuffer([]byte{})
binary.Write(bytesBuffer, binary.BigEndian, x)
//字节转整形var y int32
binary.Read(bytesBuffer, binary.BigEndian, &y)
接口到具体类型的转换
//由接口类型转换为具体的类型var i interface{} = 1
t, f := i.(int)
if f { //转换成功
fmt.Println(t)
} else {//转换失败
fmt.Println(reflect.TypeOf(i).Kind(), reflect.TypeOf(i))
}


微信搜索公众号 "技术人技术事",阅读更多精彩文章

GitHub上优秀的Go开源项目

有只黑白猫 发表了文章 • 0 个评论 • 813 次浏览 • 2019-12-31 16:28 • 来自相关话题

点击这里,查看剩余8条优秀开源项目 ...查看全部

点击这里,查看剩余8条优秀开源项目

简介:近一年来,学习和研究Go语言,断断续续的收集了一些比较优秀的开源项目,这些项目都非常不错,可以供我们学习和研究Go用,从中可以学到很多关于Go的使用、技巧以及相关工具和方法。我把他们整理发出来,大家有兴趣可以根据自己的爱好选择一些进行研究和阅读,提升自己的能力,更好的使用Go语言,开发出更优秀的项目。

docker
无人不知的虚拟华平台,开源的应用容器引擎,借助该引擎,开发者可以打包他们的应用,移植到任何平台上。

 ●  https://github.com/docker/docker
 ●  38154 stars
 ●  11393 forks
golang
go本身,也是用go语言实现的,包括他的编译器,要研究go源代码的可以看此项目录
 ●  https://github.com/golang/go
 ●  23082 stars
 ●  3081 forks
lantern
蓝灯,一款P2P的过墙软件,他和SS不一样的是,他是分布式的,P2P的,通过蓝灯,你可以和自由上网的用户共享网络,对方可以自由上网,你也就自由了。
 ●  https://github.com/getlantern/lantern
 ●  21479 stars
 ●  5573 forks
kubernetes
Google出品,用于调度和管理docker的开源容器管理系统,利用他,可以方便的管理你的docker实例,哪怕非常多,也是目前最流行的docker管理系统。
 ●  https://github.com/kubernetes/kubernetes
 ●  19513 stars
 ●  6540 forks
awesome-go
这不是一个go项目,他是一个学习go的资料网站,属于著名的awesome系列,里面关于go的资源非常详细。
 ●  https://github.com/avelino/awesome-go
 ●  17182 stars
 ●  2154 forks
gogs
一款基于git的代码托管系统,类似于github和gitlab,不过其小巧易用,功能强大,部署方便,也有不少用户在使用。
 ●  https://github.com/gogits/gogs
 ●  17004 stars
 ●  1887 forks
syncthing
开源的文件同步系统,它使用了其独有的对等自由块交换协议,速度很快,据说可以替换BitTorrent Sync。
 ●  https://github.com/syncthing/syncthing
 ●  14399 stars
 ●  1117 forks
hugo
一款极速的静态页面生成器,让你可以很快的搭建个人网站,提供了多套主题可供使用,并且可以自己定制,和NodeJS的Hexo是一样的。
 ●  https://github.com/spf13/hugo
 ●  13926 stars
 ●  2110 forks
grafana
一款开源监控度量的看板系统,可以接Graphite,Elasticsearch,InfluxDB等数据源,定制化很高。
 ●  https://github.com/grafana/grafana
 ●  13659 stars
 ●  2133 forks
etcd
一款分布式的,可靠的K-V存储系统,使用简单,速度快,又安全。
 ●  https://github.com/coreos/etcd
 ●  11837 stars
 ●  2148 forks
hub
一款更便捷使用github的工具,包装并且扩展了git,提供了很多特性和功能,使用和git差不多。
 ●  https://github.com/github/hub
 ●  9630 stars
 ●  881 forks
influxdb
可伸缩的数据库,使用场景主要用来存储测量数据,事件点击以及其他等实时分析数据,用来做监控性能很不错。
 ●  https://github.com/influxdata/influxdb
 ●  9501 stars
 ●  1330 forks
caddy
快速的,跨平台的HTTP/2 Web服务器。
 ●  https://github.com/mholt/caddy
 ●  9322 stars
 ●  607 forks  

关键字:Web App开发 监控 Go 数据库 容器