加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

golang 标准库间依赖的可视化展示

发布时间:2020-12-16 19:08:29 所属栏目:大数据 来源:网络整理
导读:简介 国庆看完 Go 语言圣经 ,总想做点什么,来加深下印象.以可视化的方式展示 golang 标准库之间的依赖,可能是一个比较好的切入点.做之前,简单搜了下相关的内容,网上也要讨论,但是没有发现直接能拿过来用的.标准库之间,是必然存在依赖关系的,不同库被依赖的程

简介

国庆看完 << Go 语言圣经 >>,总想做点什么,来加深下印象.以可视化的方式展示 golang 标准库之间的依赖,可能是一个比较好的切入点.做之前,简单搜了下相关的内容,网上也要讨论,但是没有发现直接能拿过来用的.标准库之间,是必然存在依赖关系的,不同库被依赖的程度必然是不一样的.但究竟有多大差别呢?

以下内容,数据源自真实环境的 golang 1.9 版本的标准库.所以,本文不仅是一篇可视化相关的讨论文章,更是提供了一个可以直接探究 golang 标准库间依赖关系的快速梳理工具.

数据准备

标准库各个包之间的相互关系,可以直接通过命令获取,然后简单变换为一个标准的 JSON 对象:

go list -json  std

示例输出:

{
	"Dir": "/usr/local/go/src/archive/tar","ImportPath": "archive/tar","Name": "tar","Doc": "Package tar implements access to tar archives.","Target": "/usr/local/go/pkg/darwin_amd64/archive/tar.a","Goroot": true,"Standard": true,"StaleReason": "standard package in Go release distribution","Root": "/usr/local/go","GoFiles": [
		"common.go","format.go","reader.go","stat_atimespec.go","stat_unix.go","strconv.go","writer.go"
	],"IgnoredGoFiles": [
		"stat_atim.go"
	],"Imports": [
		"bytes","errors","fmt","io","io/ioutil","math","os","path","sort","strconv","strings","syscall","time"
	],"Deps": [
		"bytes","internal/cpu","internal/poll","internal/race","path/filepath","reflect","runtime","runtime/internal/atomic","runtime/internal/sys","sync","sync/atomic","time","unicode","unicode/utf8","unsafe"
	],"TestGoFiles": [
		"reader_test.go","strconv_test.go","tar_test.go","writer_test.go"
	],"TestImports": [
		"bytes","crypto/md5","internal/testenv","testing","testing/iotest","XTestGoFiles": [
		"example_test.go"
	],"XTestImports": [
		"archive/tar","bytes","log","os"
	]
}

梳理过的数据源,参见: https://raw.githubusercontent.com/ios122/graph-go/master/data.js

可视化原理

主要涉及一下内容:

  • 可视化显示,使用的是 echarts

  • 使用原始数据的 ImportPath 而不是 Name,来作为每个数据节点的唯一id.这样是因为 golang 本身的包命名规范决定的.

  • 使用原始数据的 Imports 字段,来确定标准库包与包之间的相互依赖关系.golang是不允许循环依赖的,所以一些循环依赖相关的问题,不需要考虑.

  • 节点的大小,和包被其他包引入的次数成正相关.这样做,被依赖越多的包,图上最终显示时,就会越大.常用包和不常用包,一目了然.

数据整理

就是把原始数据,处理成 echarts 需要的数据,这里简要说下最核心的思路:

  • echarts 显示相关的代码,很大程度上参考了 graph-npm

  • 节点坐标和颜色,采用随机坐标和颜色,以去除节点和包之间的联系.我认为这样处理,能更纯粹地观察标准库包与包之间的联系.

  • 需要一个 edges 来记录包与包之间的依赖关系.在每次遍历 Imports 时,动态写入.

  • 需要一个 nodes 来记录包自身的一些信息,但是其 size 参数,需要计算过所有依赖关系后再填入.

  • 使用 nodedSize 来记录每个包被依赖的次数,为了提升效率,它是一个字典Map.

/* 将原始数据,转换为图标友好的数据. 
	ImportPath 作为唯一 id 和 标签;
	Imports 用于计算依赖关系;
	节点的大小,取决于被依赖的次数;
	*/
function transData(datas){
	/* 存储依赖路径信息. */
	let edges = []

	/* 存储基础节点信息. */
	let nodes = []

	/* 节点尺寸.初始是1,每被引入一次再加1. */
	let nodedSize = {}

	/* 尺寸单位1. */
	let unitSize = 1.5

	datas.map((data)=>{
		let itemId = data.ImportPath

		nodes.push({
			"label": itemId,"attributes": {},"id": itemId,"size": 1
		})

		if(data.Imports){
			data.Imports.map((importItem)=>{
				edges.push({
					"sourceID": importItem,"targetID": itemId,"size": unitSize
				})

				if(nodedSize[importItem]){
					nodedSize[importItem] = nodedSize[importItem] + unitSize
				}else{
					nodedSize[importItem] = unitSize
				}
			})
		}
	})

	/* 尺寸数据合并到节点上. */
	nodes.map((item)=>{
		let itemId = item.id
		if(nodedSize[itemId]){
			item.size = nodedSize[itemId]
		}
	})

	return {
		nodes,edges
	}
}

效果与源码

  • github 源码: https://github.com/ios122/graph-go
  • echarts 在线预览: http://gallery.echartsjs.com/editor.html?c=xSyJNqh8nW

相关链接

  • echarts
  • graph-npm

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读