http://www.chinaaet.com/article/3000087559

0 引言

CPU是电子产品的核心,代表着信息产业的发展水平。CPU发展至今已经有四十多年的历史了,实际就是Intel公司的发展历史[1]。Intel的CPU和其兼容产品占领了PC的大半江山。我国CPU战略已经发展十余年,部分领域完全具有核心技术,产业化取得积极进展,但是与国际主流厂商Intel等仍存在较大差距。国产CPU由于受多方因素制约,单核性能并不高,在2000年左右所有的微处理器厂商都转向了多核微处理器的开发。为提升CPU性能,国产CPU均为多核设计。目前,部分产品虽然在党政军部门及重要的信息系统有所应用,但是由于产业生态还未建立,所应用的场景还比较简单,可用于开发应用的编程语言也较为单一。国产CPU的发展事关我国信息产业的核心竞争力和可持续发展力。为了充分发挥国产CPU的性能,需要通过并行编程来解决。

Go语言设计目标之一就是多核编程,不使用多线程编程模型,通过基于CSP的communication通道并发编程,使得并发编程更加简便。Go语言原生支持广泛应用的X86、X64指令集,而且支持龙芯的MIPS64及飞腾的ARM64指令集。这使得Go语言程序在跨平台移植上天生具有优势。Go语言的其他一些特性使得其在国产CPU平台应用具有非常广泛的前景。

1 Go语言简介

Go语言是2009年11月Google正式宣布推出的一种编程语言。它的并发机制使得编写能够充分利用多核和网络通信的程序变得非常容易。Go语言是静态类型的语言,它的类型系统没有层级,完全垃圾回收,比典型的面向对象语言更轻量级;Go语言是一种编译型语言,它结合了解释型语言的游刃有余,动态类型语言的开发效率,以及静态类型的安全性。

Go编译器支持包括:x86、x64、ARM、arm64、ppc64、ppc64le、mips、mipsle、mips64、mips64le、s390x多种不同的CPU指令集。可以支持包括FreeBSD、Linux、Solaris和Windows等的多种操作系统。Go语言是跨平台、跨操作系统的语言,部署非常简单。Go 编译生成的是一个静态可执行文件,除了glibc外没有其他外部依赖。Go的并发性好,而且goroutine 和 channel 使得编写高并发的服务端软件变得相当容易,非常适合用来服务器编程。目前Go语言已经成功的项目包括目前比较流行的云框架Docker、NSQ等分布式框架等。

2 国产CPU平台简介及应用现状

目前,我国自主研发的处理器芯片主要包括龙芯(MIPS64指令集)、申威(Alpha指令集)、飞腾(ARM64指令集)及兆芯(X86指令集)4类。商用领域基于龙芯3B1500 CPU、飞腾FA1500A CPU生产的商用服务器占据国产服务器主流位置,龙芯、飞腾服务器分别搭载中标麒麟及银河麒麟操作系统。

在商用领域,全国产化平台刚刚起步,配套的商用软件较少,没有建立起完整的产业生态,同时又受到处理器自身性能的影响,基于上述两款主流处理器平台的服务器,主要还是用于对系统访问并发及响应时间要求不高的Web网站类网络应用服务。国产处理器应用服务的开发还是以Java语言为主,搭配开源JBoss、Ttomcat或国产中间件,数据库采用国产数据库或MySQL等开源数据库。

3 Go语言在国产平台的优势

3.1 国产平台现有的编程语言匮乏

目前,基于国产CPU的国产化平台比较成熟的仅有C、C++编译器。厂商对Java虚拟机在国产平台上进行编译、适配及优化。由于Java应用运行过程中依赖的大量Java第三方框架都是源于X86构架体系,并未针对国产CPU进行优化,一些应用在大压力或大并发等某些场景下会出现假死、宕机等情况,严重影响应用的正常运行。虽然国产平台也支持其他编程语言如Python、PHP等,但这类脚本语言的解释器也是交叉编译获得的,并非自身支持,在进行跨平台交叉编译过程中会遇到各种问题,很多问题需要软件开发人员修改软件源代码,未经过大量适配验证,很难保证其开发的应用的稳定性。

3.2 Go语言的跨平台及并发优势

Go语言原生支持龙芯CPU的MIPS64le指令集和飞腾CPU的ARM64指令集,天生具有跨平台优势。Go开发应用在任意平台开发完成后,直接编译,编译后的二进制文件在同类平台可直接拷贝运行,无需再次重新编译。除了glibc外,无需其他外部依赖。可以直接在该开发平台的任意计算机上运行,无需像Java运行那样需要虚拟机,需要配置复杂的环境变量;在作为网络服务时更不需要像Tomcat、Apache等的Web中间件。

Go语言的异构平台移植也非常简单,仅需要应用程序的源码,在异构平台上直接编译即可,且编译后的二进制文件在同类平台可直接拷贝运行。Go语言本身就具有天生的跨平台优势,大大降低了分布式异构计算平台的开发难度,非常适合在目前多构架的国产化平台上作为开发语言。

Go语言在并发方面,goroutine和channel机制提供了轻量级并发机制;在性能方面,与Java的性能不分上下,而内存资源消耗方面,相对Java和其他动态语言,具备明显的优势。在网络和HTTP应用方面,Go语言有良好的标准库和生态系统支持,而在标准库方面,已提供了处理多种网络所需的轻量级的代码库,对网络的核心协议HTTP的高并发支持,完全可以撼动Java。国产处理器由于指令集及工艺等多方面原因,导致单核计算性能不高,为提高整体计算能力均采用多核技术。如:龙芯3B1500为8核,商用服务器为双路16核(2颗3B1500),飞腾FT1500A服务器为16核。因此,充分利用多核计算能力或搭建基于国产处理器的云计算平台是目前国产化平台的提高整体性能发展的方向。

4 Go语言在国产环境下的移植

以飞腾平台为例,飞腾CPU采用ARM64构架。首先在X86平台上交叉编译出面向ARM64平台的Go语言自举编译工具,利用$GOOS=linux GOARCH=arm64./bootstrap.bash 编译命令编译出可在ARM64平台运行的Go语言自举编译工具,然后利用该自举编译工具在ARM64平台编译安装Go源码。安装完成后,Go语言会自动进行自身测试。测试完成后提示ALL TESTS PASSED,添加GOROOT至系统环境变量。Go语言的移植完成。龙芯平台移植过程与飞腾平台移植过程不同之处是在编译自举工具时GOARCH参数设置为MIPS64le。

5 Go语言的多核工作原理简介

Go语言可以快速高效地调用多核进行计算,其优势源于Go语言的Go runtime的调度器[2]

用户空间线程和内核空间线程之间的映射关系有N:1、1:1和M:N 3种通常的线程模型。其中N:1模型是几个用户空间线程在一个OS线程上运行。该模型上下文切换非常快速,但不能利用多核系统的优点。1:1模型一个执行线程匹配一个OS线程。 它利用机器上的所有内核,但上下文切换速度较慢,因为它必须通过操作系统进行。

Go通过使用M:N调度程序来取得上述两种方式的最佳效果。它将任意数量的goroutine调度到任意数量的OS线程上。开发者可以获得快速上下文切换,并利用系统中的所有内核。这种方法的主要缺点是增加了调度器的复杂性。

为了完成调度任务,Go Scheduler使用3个主要实体,如图1所示。

M三角形表示OS线程。这是由操作系统管理的执行线程,其工作原理与标准POSIX线程相似。

G圆圈代表一个goroutine。它包括堆栈、指令指针和其他重要的调度goroutines的信息,像任何可能被阻止的channel等。

P是从N:1调度程序进入M:N调度程序的重要部分,表示调度的上下文。可以将其视为在单个线程上运行Go代码的调度程序,一个局部的调度器。

如图2所示,有2个线程(M),每个线程都有一个上下文(P),每个线程都运行一个goroutine(G)。为了运行goroutines,线程必须持有一个上下文。

P的数量可以通过GOMAXPROCS()来设置,代表了真正的并发度,即有多少个goroutine可以同时运行。可以使用它来调整Go进程到计算机的调用,例如在4核心PC上运行4个线程的Go代码。

白色的goroutines没有运行,处于就绪状态,正在等待被调度。P维护着这个队列。在Go语言里,每当goroutine执行go语句时,goroutines都会添加到队列的末尾。一旦上下文运行了一个goroutine直到调度点,它会从其运行队列中弹出一个goroutine,设置堆栈和指令指针,并开始运行goroutine。

图3中当一个OS线程被阻塞时,P可以转而投奔另一个系统线程。从图中看到,当一个线程M0陷入阻塞时,P转而在OS线程M1上运行。调度器保证有足够的线程来运行所有P。

M1可能是被创建,或者从线程缓存中取出。当syscall返回时,它必须尝试获取一个上下文来运行返回的goroutine,一般情况下,它会从其他的系统线程取得一个上下文,如果没有获取到,它就把goroutine放在一个全局队列中,放入线程缓存里。上下文会周期性地检查全局队列,否则全局队列上的goroutine永远无法执行。

如果上下文的运行队列的工作量不平衡,如图4所示,则可能会发生这种情况。P所分配的任务G很快就执行完了(分配不均),这就导致了一个上下文P空闲而系统忙碌。当一个上下文用完时,它将尝试从另一个上下文中窃取大约一半的运行队列。这确保在每个上下文上总是有工作要做,这反过来确保所有线程都以最大容量工作,每个系统线程都能充分地使用。

6 实测Go语言在国产平台的多核调用

6.1 并行积分计算原理

并行计算积分。计算积分是一个用来展示并发编程和它本身加速度(表示的是多处理器执行时间和单处理器执行时间的比值)的常见例子,例如一个函数f(x)在[a,b]上的积分:

通过循环触发goroutine(协程)来实现np个子算组的并行运算,通过Go代码来计算Pi的积分:

6.2 Go语言并行计算核心代码实现

核心代码:

上述计算中,一个计算组是通过 block(start,end int,c chan float64)这个函数实现的,这个函数计算从start到end之间的矩形面积、通道(channl)c则是用来在结束的时候进行同步,并且把计算组的结果送到主线程。主线程通过调用rutime.GOMAXPROCS(np)建立运行时所使用的CPU核数,np为使用CPU的个数,然后通过make构造一个有np大小缓存的通道,进行阻塞,确保计算并行进行。最后把执行np次的结果进行累加以获得pi的结果。

6.3 Go语言并行计算在国产CPU多核调用测试

6.3.1 测试环境

飞腾平台:FT1500A16核×1;内存16 GB;Go编译器1.8.1;操作系统:银河麒麟4.0。

龙芯平台:3B1500A8核×2;内存16 GB;Go编译器1.8.1;操作系统:中标麒麟6.0。

6.3.2 测试方法

程序内计时,每次测试3次,取最短时间。结果如图5、图6所示。

上面两组数据图展示了,在龙芯3B1500处理器和飞腾FT1500A上,并行Go计算Pi的效率,对于小的问题规模(n=105,106),使用多核不能增加的执行时间,这是因为过多的进程调度和初始化协程导致的,大部分时间没有执行并行计算。当问题规模n变大的时候(n=108,109,1010),使用多处理器能够显著地缩短计算所需的执行时间。

6.3.3 结果对比

结果对比如图7所示。

从图7可以看出,与其他公开的测试的数据基本一致,飞腾FT1500A无论单核和多核性能均比龙芯3B1500CPU计算能力快出近一倍。

6.4 Go语言在调用多核进行并行计算的性能线性特性

为了能够体现并发执行的加速度,以飞腾F1500A为例子以通过式(6)计算速度:

在这里Tnp和TMaxnp是处理器当前使用核数计算所用时间和处理器最大核数计算所用时间。结果如图8所示。

在图8中,当问题规模非常大的时候,增长几乎就是线性的了,特别是问题规模达到(n=109)的时候,几乎和拟合趋势线重合。

7 结束语

本文对Go语言在多线程领域编程、跨异构平台及编程难易程度的优势进行了阐述;对目前我国国产CPU在商业化应用领域现状进行了分析。使用Go语言在主流两款国产平台对多核调用进行测试。同时,对Go语言的多核工作原理进行了简要分析。综上所述,Go语言非常适合作为除Java外的另一种国产CPU平台应用开发语言,有较为广泛的应用前景。本文对未来Go语言在国产CPU平台上的开发及应用提供了一定的参考价值。

参考文献

[1] 芮雪,王亮亮,杨琴.国产处理器研究与发展现状综述[J].现代计算机(普及版),.2014(3):15-19.

[2] MORSING D.The Go scheduler[Z].2013.

Go语言在国产CPU平台上应用前景的探索与思考的更多相关文章

  1. 异数OS国产CPU平台移植项目需求分析

    异数OS国产CPU平台移植项目需求分析 目录 异数OS国产CPU平台移植项目需求分析 项目立项背景 项目需求分析 异数OS性能指标简介 1.TCP协议栈性能测试 2.异数OS-织梦师-水母 消息队列性 ...

  2. 国产CPU走到十字路口:谁来取代英特尔芯片?(少写了一个OpenPower)

    国内的几支CPU研发力量各自选择的指令体系都有自己的优点和问题,选择其中的哪一支都会有对应的成本和风险.最终谁能担大任,且拭目以待. 文 | 瞭望智库特约科技观察员 王强 用上内置国产CPU的个人电脑 ...

  3. 如何在国产龙芯架构平台上运行c/c++、java、nodejs等编程语言

    高能预警:本文内容过于硬核,涉及编译器原理.cpu指令集.机器码.编程语言原理.跨平台原理等计算机专业基础知识,建议具有c.c++.java.nodejs等多种编程语言开发能力,且实战经验丰富的资深开 ...

  4. JVM 平台上的各种语言的开发指南

    JVM 平台上的各种语言的开发指南 为什么我们需要如此多的JVM语言? 在2013年你可以有50中JVM语言的选择来用于你的下一个项目.尽管你可以说出一大打的名字,你会准备为你的下一个项目选择一种新的 ...

  5. JAVA平台上的网络爬虫脚本语言 CrawlScript

    JAVA平台上的网络爬虫脚本语言 CrawlScript 网络爬虫即自动获取网页信息的一种程序,有很多JAVA.C++的网络爬虫类库,但是在这些类库的基础上开发十分繁琐,需要大量的代码才可以完成一 个 ...

  6. 龙芯GO!龙芯平台上构建Go语言环境指南

    龙芯软件生态系列——龙芯GO!龙芯平台上构建Go语言环境指南2016-07-05 龙芯中科1初识Go语言Go语言是Google公司于2009年正式推出的一款开源的编程语言,是由Robert Gries ...

  7. Linux平台上常用到的c语言开发程序

    Linux操作系统上大部分应用程序都是基于C语言开发的.小编将简单介绍Linux平台上常用的C语言开发程序. 一.C程序的结构1.函数 必须有一个且只能有一个主函数main(),主函数的名为main. ...

  8. [转自知乎]飞腾国产CPU的部分知识

    1. 作者:常成链接:https://www.zhihu.com/question/48948852/answer/113595308来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载 ...

  9. 不权威的国产CPU发展历程

    最近进行了一些国产化相关工作 趁着周末有时间,自己整理一下这段时间的学习内容. 毕竟不是处理器和芯片的业内人士,里面多有纰漏,请谅解. 希望可以作为入门学习的简单知识. 1.0 远古时代 unix 世 ...

随机推荐

  1. SQL"已更新或者删除的行值要么不能使该行成为唯一行,要么改变了多个行(X行)“解决办法

    这种问题大多是由于没有主键(PK)导致同一张表中存在若干条相同的数据.DBMS存储时,只为其存储一条数据,因为DBMS底层做了优化,以减少数据冗余.所以删除或更新一条重复数据就牵一发而动全身. 解决方 ...

  2. 【笔试题】Java Data Types

    Java 知识测试 Java Data Types Question 1 Predict the output of the following program. class Test { publi ...

  3. Redis解决“重试次数”场景的实现思路

    很多地方都要用到重试次数限制,不然就会被暴力破解.比如登录密码. 下面不是完整代码,只是伪代码,提供一个思路. 第一种(先声明,这样写有个bug) import java.text.MessageFo ...

  4. [转帖]Linux中buff/cache内存占用过高解决办法

    Linux中buff/cache内存占用过高解决办法 https://www.cnblogs.com/rocky-AGE-24/p/7629500.html /proc/sys/vm/drop_cac ...

  5. Oracle将小于1的数字to_char后,丢掉小数点前0的解决办法

    使用to_char方法将小于0的数字转化为字符串时会出现小数点前0丢失的问题: 解决方案: 使用 oracle的tochar() 函数,并指定位数. --解决方案: 使用 oracle的tochar( ...

  6. golang学习笔记 ---常用第三方包

    包的介绍 包类似Java中概念,jar是源代码管理,分发的最小单位. 目前多数包来自 Github官方包来自 golang.org/x/... 可以在如下网址查询到高频使用的第三方包清单https:/ ...

  7. java之mybatis之动态sql

    1. if 判读条件是否满足,满足将会把 sql 语句加上. <select id="findUser" parameterType="Map" resu ...

  8. python 3.url了解与基础使用

    URL使用 视图: 我们运行项目在网页上查看到的我们称之为视图 视图一般在views.py下编辑 它的第一个参数永远都是request,通过它请求一些数据返回给网页给我们查看. 视图函数的返回结果必须 ...

  9. Mybatis中使用association进行关联的几种方式

    这里以一对一单向关联为例.对使用或不使用association的配置进行举例.  实体类: @Data @ToString @NoArgsConstructor public class IdCard ...

  10. nginx+rsync实现本地yum源以及公网yum源

    1.配置nginx的autoindex模块,开启目录浏览功能 2.使用rsync同步公网源上的软件包,至本地目录中 3.配置客户端指向即可 1.nginx提供目录浏览功能 [root@xuliangw ...