go语言开发入门
go语言开发入门
每个Go程序包含一个名为main的包以及其main函数,在初始化后,程序从main开始执行,避免引入不使用的包(编译不通过)
基础语法
基本数据类型
bool, byte
int,int8,int16,int32,int64
uint8,uint16,uint32,uint64
float32,float64(没有float类型)
string
变量赋值
var a
a = 12
a := 12
a,b :=12,23
常量赋值
const(
a = iota
b
)
循环只有 for
for i:=0;i<10;i++{
do Something...
}
for{
//相当于while(true){}
}
for _,v:= range list{
//range用法返回list数组或者列表的k,v两个值(k数组索引从0开始,v值)
fmt.Print("%s", v)
}
选择 if 和 switch
a := 1
b := 1
if a+b > 2 {
// 注:if(条件不带括号,且左大括号与if保持同行)
}
- 学习一门语言学会循环
完整demo 大白加大白等于白胖胖.求大,白,胖各是数字多少?
package main
import (
"fmt"
"strconv"
)
/* 大白加大白等于白胖胖.求大,白,胖各是数字多少? */
func main() {
for d := 1; d < 10; d++ {
for b := 1; b < 10; b++ {
for p := 1; p < 10; p++ {
daBai, _ := strconv.Atoi(strconv.Itoa(d) + strconv.Itoa(b))
// fmt.Println("大白", daBai)
baiPangPang, _ := strconv.Atoi(strconv.Itoa(b) + strconv.Itoa(p) + strconv.Itoa(p))
// fmt.Println("白胖胖", baiPangPang)
if daBai+daBai == baiPangPang {
fmt.Println("-------------------大 白 胖--------------------")
fmt.Printf("大 = %d, 白 = %d, 胖 = %d\n", d, b, p)
fmt.Println("白胖胖: ", baiPangPang)
}
}
}
}
}
数据(array)与切片(slice)
数组声明:ArrayType = "[" ArrayLength "]" ElementType .
var a [32] int
var b [3][5] int
(1)数组是值类型。将一个数组赋值给另一个,会拷贝所有的元素.
(2) 如果你给函数传递一个数组,其将收到一个数组的拷贝,而不是它的指针.
(3)数组的大小是其类型的一部分,类型[10]int和[20]int是不同的。数组长度在声明后,就不可更改.
切片声明:SliceType = "[" "]" ElementType .
var a []int
(1)没有初始化的slice为nil.
(2)切片(slice)对数组进行封装,实际上,切片可以看成大小可以动态变化的数组.
(3)Go中大多数的数组编程都是通过切片完成,而不是简单数组.
一般来说,有两种方式来初始化切片:
//通过数组方式
var myArray [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
var mySlice []int = myArray[:5]
//make方式
make([]T, length, capacity)
Channel
Goroutine和channel是Go在“并发”方面两个核心feature。
Channel是goroutine之间进行通信的一种方式,go所提倡的"应该以通信作为手段来共享内存"的最直接体现。
Channel声明:
ChannelType = ( "chan" | "chan" "<-" | "<-" "chan" ) ElementType .
var ch chan int
var ch1 chan<- int //ch1只能写
var ch2 <-chan int //ch2只能读
//make初始化
putnamechan := make(chan string, 100) //带缓冲
Goroutine
关键字go,启用Goroutine的唯一途径
//同时向五个人打招呼
func main(){
names := []string{"Eric","Tom","Jack","Jim"}
for _,name:= range names{
go func(){
fmt.Printf("Hello,%s.\n",name)
}()
}
runtime.Gosched()
}
调度模型
Go的调度器内部有三个重要的结构:M,P,S
M:代表真正的内核OS线程,真正干活的人
G:代表一个goroutine,它有自己的栈,instruction pointer和其他信息(正在等待的channel等等),用于调度。
P:代表调度的上下文,可以把它看做一个局部的调度器,使go代码在一个线程上跑,它是实现从N:1到N:M映射的关键。

图中看,有2个物理线程M,每一个M都拥有一个context(P),每一个也都有一个正在运行的goroutine。
P的数量可以通过GOMAXPROCS()来设置,它其实也就代表了真正的并发度,即有多少个goroutine可以同时运行。
图中灰色的那些goroutine并没有运行,而是出于ready的就绪态,正在等待被调度。P维护着这个队列(称之为runqueue),
Go语言里,启动一个goroutine很容易:go function 就行,所以每有一个go语句被执行,runqueue队列就在其末尾加入一个
goroutine,在下一个调度点,就从runqueue中取出一个goroutine执行。
其他
- defer语句:调用一个被 defer 的函数时在函数刚要返回之前延迟执行
- panic/recover 异常处理语句
缺陷
- 编译生成的可执行文件尺寸非常大
- 代码可读性差(x,y,z int, a []*struct)
- go的滥用导致不可预见bug(注goroutine的使用应该是保守型的)
有两种思维逻辑会想到使用goroutine
- 业务逻辑需要并发
比如一个服务器,接收请求,阻塞式的方法是一个请求处理完成后,才开始第二个请求的处理。其实在设计的时候我们一定不会这么做,我们会在一开始就已经想到使用并发来处理这个场景,每个请求启动一个goroutine为它服务,这样就达到了并行的效果。这种goroutine直接按照思维的逻辑来使用goroutine
- 性能优化需要并发
一个场景是这样:需要给一批用户发送消息,正常逻辑会使用
for _, user := range users {
sendMessage(user)
}
//但是在考虑到性能问题的时候,我们就不会这样做,如果users的个数很大,比如有1000万个用户?我们就没必要将1000万个用户放在一个routine中运行处理,考虑将1000万用户分成1000份, //每份开一个goroutine,一个goroutine分发1万个用户,这样在效率上会提升很多。这种是性能优化上对goroutine的需求
实例httpmq
http协议实现的消息队列,数据持久化levelDb
//httpmq
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
} //net/http包起路由做拦截处理(put,get,status,view)
//接收name\data参数
//起四个channel
putnamechan := make(chan string, 100) //入队name管道
putposchan := make(chan string, 100) //入队数据索引管道
getnamechan := make(chan string, 100) //出队name管道
getposchan := make(chan string, 100) //出队数据索引管道
//两个Goroutine做消息管道流入队出队操作
go func(chan string, chan string) {
for {
name := <-putnamechan //
putpos := httpmq_now_putpos(name)
putposchan <- putpos
}
}(putnamechan, putposchan)
go func(chan string, chan string) {
for {
name := <-getnamechan
getpos := httpmq_now_getpos(name)
getposchan <- getpos
}
}(getnamechan, getposchan)
//put入队操作
putnamechan <- name
putpos := <-putposchan
queue_name := name + putpos
if data != "" {
db.Put([]byte(queue_name), []byte(data), nil)
} else if len(buf) > 0 {
db.Put([]byte(queue_name), buf, nil)
}
//get出队操作
getnamechan <- name
getpos := <-getposchan
if getpos == "0" {
w.Write([]byte("HTTPMQ_GET_END"))
} else {
queue_name := name + getpos
v, err := db.Get([]byte(queue_name), nil)
if err == nil {
w.Header().Set("Pos", getpos)
w.Write(v)
} else {
w.Write([]byte("HTTPMQ_GET_ERROR"))
}
}
put操作
name --> putnameChannel --> 生成putPos --> putposChannel --> name+pos生成key持久化data
get操作
name --> getnameChannel --> 生成getPos --> getposChannel --> name+pos生成key getData
go语言开发入门的更多相关文章
- Scala语言开发入门
在本系列的第一篇文章 <使用递归的方式去思考>中,作者并没有首先介绍 Scala 的语法,这样做有两个原因:一是由于过多的陷入语法的细节其中,会分散读者的注意力.反而忽略了对于基本概念,基 ...
- Kotlin 语言高级安卓开发入门
过去一年,使用 Kotlin 来为安卓开发的人越来越多.即使那些现在还没有使用这个语言的开发者,也会对这个语言的精髓产生共鸣,它给现在 Java 开发增加了简单并且强大的范式.Jake Wharton ...
- Mac电脑C语言开发的入门帖
本文是写给Mac电脑开发新手的入门帖,诸神请退散. C语言 C语言可说是电脑环境中的"镇国神器",从发明至今,虽然C语言的使用者缓慢的减少,但从当前市场应用情况看,尚无一台电脑能够 ...
- Swift语言快速入门
Swift语言快速入门(首部同步新版官方API文档和语法的Swift图书,确保代码可编译,作者专家在线答疑,图书勘误实时跟进) 极客学院 编著 ISBN 978-7-121-24328-8 201 ...
- VR原理讲解及开发入门
本文是作者obuil根据多年心得专门为想要入门的VR开发者所写,由52VR网站提供支持. 1. VR沉浸感和交互作用产生的原理: 在之前,我们观看一个虚拟的创造内容是通过平面显示器的,52VR ...
- [Cordova] Plugin开发入门
[Cordova] Plugin开发入门 Overview Cordova的设计概念,是在APP上透过Web控件来呈现Web页面,让Web开发人员可以操作熟悉的语言.工具来开发APP.使用Web页面来 ...
- JavaWeb学习总结(一)——JavaWeb开发入门
http://www.cnblogs.com/xdp-gacl/p/3729033.html 只为成功找方法,不为失败找借口! JavaWeb学习总结(一)--JavaWeb开发入门 一.基本概念 1 ...
- HTML5手机APP开发入门(1)
HTML5手机APP开发入门(1) 开发框架 Ionicframework V2 + Angular 2 具体内容可以参考一下网站 http://ionicframework.net/ http:// ...
- 基于Nodejs生态圈的TypeScript+React开发入门教程
基于Nodejs生态圈的TypeScript+React开发入门教程 概述 本教程旨在为基于Nodejs npm生态圈的前端程序开发提供入门讲解. Nodejs是什么 Nodejs是一个高性能Ja ...
随机推荐
- CF321E Ciel and Gondolas Wqs二分 四边形不等式优化dp 决策单调性
LINK:CF321E Ciel and Gondolas 很少遇到这么有意思的题目了.虽然很套路.. 容易想到dp \(f_{i,j}\)表示前i段分了j段的最小值 转移需要维护一个\(cost(i ...
- 笨办法学python3代码练习ex23.py 字符串字节串字符编码
首先简单说一下字符编码的问题.平常遇到比较多的就是ASCII码(全称:美国信息交换标准码).ASCII码使用一个字节(8位)来表示一些常见的数字.英文字母以及一些控制字符.英语用128个符号编码就够了 ...
- 查看 Linux 系统服务的 5 大方法
Linux 系统服务有时也称为守护程序,是在Linux启动时自动加载并在Linux退出时自动停止的系统任务. 在本文中,良许将为大家介绍如何列出 Linux 系统里所有运行的服务,以及如何检查某个服务 ...
- “随手记”开发记录day20
练习软件的展示,尽量将软件全方面的展示给大众,希望不要像上次一样有许多遗漏的地方,让其他团队以为我们的软件没有完善的功能.
- Spring IoC是如何进行依赖注入的
依赖注入(DI) DI(Dependency Injection),Spring IoC 不是一种技术,而是一种思想,通过这种思想,能够指导我们设计出松耦合的程序代码.而Spring IoC这个思想的 ...
- 了解学习 Javascript, ES5 和 ES6之间的亲密关系
什么是Javascript JavaScript一种动态类型.弱类型.基于原型的客户端脚本语言,用来给HTML网页增加动态功能. JavaScript 的标准是 ECMAScript.截至 201 ...
- 牛客 51011 可达性统计(拓扑排序,bitset)
牛客 51011 可达性统计(拓扑排序,bitset) 题意: 给一个 n个点,m条边的有向无环图,分别统计每个点出发能够到达的点的数量(包括自身) \(n,m\le30000\). 样例: 10 1 ...
- FSAF
Feature Selective Anchor-Free Module for Single-Shot Object Detection https://zhuanlan.zhihu.com/p/5 ...
- java 序列化流与反序列化流
一 对象序列化流ObjectOutputStream ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream.可以使用 ObjectInputStr ...
- sftp与ftp的区别
SFTP和FTP非常相似,都支持批量传输(一次传输多个文件),文件夹/目录导航,文件移动,文件夹/目录创建,文件删除等.但还是存在着差异,下面我们来看看SFTP和FTP之间的区别. 1. 安全通道FT ...