1.解Go里面的语言源码语言源码WaitGroup了解编程语言核心实现源码
2.go语言零基础教程:第一个程序:HelloWorld
3.go源码:Sleep函数与线程
4.Go并åç¼ç¨ï¼goroutineï¼channelåsync详解
5.golangç½ç»ç¼ç¨(golangç¼ç¨è¯è¨)
6.通过etcd源码学习golang编程——build constraint
解Go里面的WaitGroup了解编程语言核心实现源码
sync.WaitGroup核心实现逻辑简单,主要用于等待一组goroutine退出。编程它通过Add方法指定等待的分析goroutine数量,Done方法递减计数。语言源码语言源码计数为0时,编程等待结束。分析查看框架的源码sync.WaitGroup内部使用了一个state1数组,语言源码语言源码其中只有一个元素,编程类型为[3]uint。分析这是语言源码语言源码为了内存对齐,确保数据按照4字节对齐,编程从而在位和位平台间兼容。分析
内部元素采用uint类型进行计数,语言源码语言源码长度为8字节。编程这是分析为了防止在位平台上对字节的uint操作可能不是原子的情况。使用uint保证了原子操作的执行和性能。在CPU缓存线(cache line)的上下文中,8字节长度可能有助于确保对缓存线的操作是原子的,从而避免数据损坏。
测试8字节指针的构造,验证了在经过编译器进行内存分配对齐后,如果元素指针的阅读源码价值分析地址不能被8整除,则其地址+4可以被8整除。这展示了编译器层内存对齐的实现细节。
sync.WaitGroup中的8字节uint采用分段计数的方式,高位记录需要Done的数量,低位记录正在等待结束的计数。
源码的核心原理包括使用位uint进行计数,通过高位记录需要Done的数量和低位记录等待的数量。当发现count>0时,Wait的goroutine会排队等待。任务完成后,goroutine执行Done操作,直到count==0,完成并唤醒所有等待的goroutine。
计数与信号量的实现通过根据当前指针的地址确定采用哪个分段进行计数和等待。添加等待计数和Done完成等待事件分别对应sync.WaitGroup的Add和Done方法。等待所有操作完成时,sync.WaitGroup确保所有任务完成。
为了深入理解这些概念,可以参考相关文章和资源,如关于CPU缓存线大小和原子操作的讨论。此外,getpost链接跳转源码更多源码分析文章可关注特定的公告号或网站,如www.sreguide.com。本篇文章由ArtiPub自动发布平台发布。
go语言零基础教程:第一个程序:HelloWorld
在开始学习使用Go语言进行编程时,首要的任务是配置好工作目录,并了解Go语言的通用项目结构。Go项目的结构主要包含源代码资源文件存放的目录结构。在Go环境中,有一个关键的目录,即gopath目录,用于存储编写的源代码,通常包含三个子目录:src、bin和pkg。
src目录下,每个子目录代表一个包,包内存放Go源码文件。pkg目录存储编译后生成的目标文件,而bin目录则存放生成的可执行文件。
为了编写第一个程序,首先在gopath目录下创建src目录,并在其中创建一个名为hello的ugui源码多少行文件夹。在hello文件夹内创建一个文件,命名为helloworld.go,然后双击打开并输入程序代码。
执行Go程序有两种方式。一种是使用go run命令,步骤如下:打开终端,对于Windows用户使用快捷键win+R输入cmd,对于Linux用户使用快捷键ctrl+alt+T,对于Mac用户使用command+空格输入terminal。接着进入helloworld.go所在的目录,并在终端中输入go run helloworld.go命令,运行结果即可显示。
另一种方式是使用go build命令,步骤如下:在任意文件路径下运行go install hello(如果项目在当前路径下则可省略路径信息)。进入项目(应用包)路径后,运行go install命令。程序编译时,Go会查找两个地方:GOROOT下的src文件夹以及GOPATH下的src文件夹中的程序包。自动寻找main包的main函数作为程序入口进行编译。编译完成后,在/home/go/bin/目录下生成了一个可执行文件hello,rfid资产管理源码通过运行./hello即可执行程序。
在编写程序时,需要导入必要的包。例如,import "fmt"表示程序需要使用fmt包的函数,该包提供了格式化IO(输入/输出)的功能。导入路径可以是相对路径或绝对路径,推荐使用绝对路径。
main函数是程序运行的入口。在程序中定义main函数,Go编译器会自动执行该函数,作为程序的开始。
在多项目开发中,通过包来组织项目目录结构。包名以网站域名开头,避免冲突。如果有自己的域名,可使用该域名;若无,通常使用个人GitHub用户名作为包名,确保包名的唯一性。
源代码存放于GOPATH的src目录下,不同包通过文件夹结构进行区分,例如以域名或GitHub用户名命名的文件夹,用于存储特定用户编写的Go源代码。
go源码:Sleep函数与线程
在探索 Go 语言的并发编程中,Sleep 函数与线程的交互方式与 Java 或其他基于线程池的并发模型有所不同。本文将深入分析 Go 语言中 Sleep 函数的实现及其与线程的互动方式,以解答关于 Go 语言中 Sleep 函数与线程关系的问题。
首先,重要的一点是,当一个 goroutine(g)调用 Sleep 函数时,它并不会导致当前线程被挂起。相反,Go 通过特殊的机制来处理这种情景,确保 Sleep 函数的调用不会影响到线程的执行。这一特性是 Go 语言并发模型中独特而关键的部分。
具体来说,当一个 goroutine 调用 Sleep 函数时,它首先将自身信息保存到线程的关键结构体(p)中并挂起。这一过程涉及多个函数调用,包括 `time.Sleep`、`runtime.timeSleep`、`runtime.gopark`、`runtime.mcall`、`runtime.park_m`、`runtime.resetForSleep` 等。最终,该 goroutine 会被放入一个 timer 结构体中,并将其放入到 p 关联的一个最小堆中,从而实现了对当前 goroutine 的保存,同时为调度器提供了切换到其他 goroutine 或 timer 的机会。因此,这里的 timer 实际上代表了被 Sleep 挂起的 goroutine,它在睡眠到期后能够及时得到执行。
接下来,我们深入分析 goroutine 的调度过程。当线程 p 需要执行时,它会通过 `runtime.park_m` 函数调用 `schedule` 函数来进行 goroutine 或 timer 的切换。在此过程中,`runtime.findrunnable` 函数会检查线程堆中是否存在已到期的 timer,如果存在,则切换到该 timer 进行执行。如果 timer 堆中没有已到期的 timer,线程会继续检查本地和全局的 goroutine 队列中是否还有待执行的 goroutine,如果队列为空,则线程会尝试“偷取”其他 goroutine 的任务。这一过程包括了检查 timer 堆、偷取其他 p 中的到期 timer 或者普通 goroutine,确保任务能够及时执行。
在“偷取”任务的过程中,线程会优先处理即将到期的 timer,确保这些 timer 的准时执行。如果当前线程正在执行其他任务(如 epoll 网络),则在执行过程中会定期检查 timer 到期情况。如果发现其他线程的 timer 到期时间早于自身,会首先唤醒该线程以处理其 timer,确保不会错过任何到期的 timer。
为了证明当前线程设置的 timer 能够准时执行,本文提出了两种证明方法。第一种方法基于代码细节,重点分析了线程状态的变化和 timer 的执行流程。具体而言,文章中提到的三种线程状态(正常运行、epoll 网络、睡眠)以及相应的 timer 执行情况,表明在 Go 语言中,timer 的执行策略能够确保其准时执行。第二种方法则从全局调度策略的角度出发,强调了 Go 语言中线程策略的设计原则,即至少有一个线程处于“spinning”状态或者所有线程都在执行任务,这保证了 timer 的准时执行。
总之,Go 语言中 Sleep 函数与线程之间的交互方式,通过特殊的线程管理机制,确保了 goroutine 的 Sleep 操作不会阻塞线程,同时保证了 timer 的准时执行。这一机制是 Go 语言并发模型的独特之处,为开发者提供了一种高效且灵活的并发处理方式。
Go并åç¼ç¨ï¼goroutineï¼channelåsync详解
ä¼é ç并åç¼ç¨èå¼ï¼å®åç并åæ¯æï¼åºè²ç并åæ§è½æ¯Goè¯è¨åºå«äºå ¶ä»è¯è¨çä¸å¤§ç¹è²ãå¨å½ä»è¿ä¸ªå¤æ ¸æ¶ä»£ï¼å¹¶åç¼ç¨çæä¹ä¸è¨èå»ã使ç¨Goå¼å并åç¨åºï¼æä½èµ·æ¥é常ç®åï¼è¯è¨çº§å«æä¾å ³é®ågoç¨äºå¯å¨åç¨ï¼å¹¶ä¸å¨åä¸å°æºå¨ä¸å¯ä»¥å¯å¨æåä¸ä¸ä¸ªåç¨ã
ä¸é¢å°±æ¥è¯¦ç»ä»ç»ã
goroutineGoè¯è¨ç并åæ§è¡ä½ç§°ä¸ºgoroutineï¼ä½¿ç¨å ³é®è¯goæ¥å¯å¨ä¸ä¸ªgoroutineã
goå ³é®è¯åé¢å¿ é¡»è·ä¸ä¸ªå½æ°ï¼å¯ä»¥æ¯æåå½æ°ï¼ä¹å¯ä»¥æ¯æ åå½æ°ï¼å½æ°çè¿åå¼ä¼è¢«å¿½ç¥ã
goçæ§è¡æ¯éé»å¡çã
å æ¥çä¸ä¸ªä¾åï¼
packagemainimport("fmt""time")funcmain(){ gospinner(*time.Millisecond)constn=fibN:=fib(n)fmt.Printf("\rFibonacci(%d)=%d\n",n,fibN)//Fibonacci()=}funcspinner(delaytime.Duration){ for{ for_,r:=range`-\|/`{ fmt.Printf("\r%c",r)time.Sleep(delay)}}}funcfib(xint)int{ ifx<2{ returnx}returnfib(x-1)+fib(x-2)}ä»æ§è¡ç»ææ¥çï¼æå计ç®åºäºææ³¢é£å¥æ°åçå¼ï¼è¯´æç¨åºå¨spinnerå¤å¹¶æ²¡æé»å¡ï¼èä¸spinnerå½æ°è¿ä¸ç´å¨å±å¹ä¸æå°æ示å符ï¼è¯´æç¨åºæ£å¨æ§è¡ã
å½è®¡ç®å®ææ³¢é£å¥æ°åçå¼ï¼mainå½æ°æå°ç»æ并éåºï¼spinnerä¹è·çéåºã
åæ¥çä¸ä¸ªä¾åï¼å¾ªç¯æ§è¡æ¬¡ï¼æå°ä¸¤ä¸ªæ°çåï¼
packagemainimport"fmt"funcAdd(x,yint){ z:=x+yfmt.Println(z)}funcmain(){ fori:=0;i<;i++{ goAdd(i,i)}}æé®é¢äºï¼å±å¹ä¸ä»ä¹é½æ²¡æï¼ä¸ºä»ä¹å¢ï¼
è¿å°±è¦çGoç¨åºçæ§è¡æºå¶äºãå½ä¸ä¸ªç¨åºå¯å¨æ¶ï¼åªæä¸ä¸ªgoroutineæ¥è°ç¨mainå½æ°ï¼ç§°ä¸ºä¸»goroutineãæ°çgoroutineéè¿goå ³é®è¯å建ï¼ç¶å并åæ§è¡ãå½mainå½æ°è¿åæ¶ï¼ä¸ä¼çå¾ å ¶ä»goroutineæ§è¡å®ï¼èæ¯ç´æ¥æ´åç»ææægoroutineã
é£æ没æåæ³è§£å³å¢ï¼å½ç¶æ¯æçï¼è¯·å¾ä¸çã
channelä¸è¬åå¤è¿ç¨ç¨åºæ¶ï¼é½ä¼éå°ä¸ä¸ªé®é¢ï¼è¿ç¨é´éä¿¡ã常è§çéä¿¡æ¹å¼æä¿¡å·ï¼å ±äº«å åçãgoroutineä¹é´çéä¿¡æºå¶æ¯ééchannelã
使ç¨makeå建ééï¼
ch:=make(chanint)//chçç±»åæ¯chanintééæ¯æä¸ä¸ªä¸»è¦æä½ï¼sendï¼receiveåcloseã
ch<-x//åéx=<-ch//æ¥æ¶<-ch//æ¥æ¶ï¼ä¸¢å¼ç»æclose(ch)//å ³éæ ç¼å²channelmakeå½æ°æ¥å两个åæ°ï¼ç¬¬äºä¸ªåæ°æ¯å¯éåæ°ï¼è¡¨ç¤ºéé容éãä¸ä¼ æè ä¼ 0表示å建äºä¸ä¸ªæ ç¼å²ééã
æ ç¼å²ééä¸çåéæä½å°ä¼é»å¡ï¼ç´å°å¦ä¸ä¸ªgoroutineå¨å¯¹åºçééä¸æ§è¡æ¥æ¶æä½ãç¸åï¼å¦ææ¥æ¶å æ§è¡ï¼é£ä¹æ¥æ¶goroutineå°ä¼é»å¡ï¼ç´å°å¦ä¸ä¸ªgoroutineå¨å¯¹åºééä¸æ§è¡åéã
æ以ï¼æ ç¼å²ééæ¯ä¸ç§åæ¥ééã
ä¸é¢æ们使ç¨æ ç¼å²ééæä¸é¢ä¾åä¸åºç°çé®é¢è§£å³ä¸ä¸ã
packagemainimport"fmt"funcAdd(x,yint,chchanint){ z:=x+ych<-z}funcmain(){ ch:=make(chanint)fori:=0;i<;i++{ goAdd(i,i,ch)}fori:=0;i<;i++{ fmt.Println(<-ch)}}å¯ä»¥æ£å¸¸è¾åºç»æã
主goroutineä¼é»å¡ï¼ç´å°è¯»åå°ééä¸çå¼ï¼ç¨åºç»§ç»æ§è¡ï¼æåéåºã
ç¼å²channelå建ä¸ä¸ªå®¹éæ¯5çç¼å²ééï¼
ch:=make(chanint,5)ç¼å²ééçåéæä½å¨ééå°¾é¨æå ¥ä¸ä¸ªå ç´ ï¼æ¥æ¶æä½ä»ééç头é¨ç§»é¤ä¸ä¸ªå ç´ ãå¦æéé满äºï¼åéä¼é»å¡ï¼ç´å°å¦ä¸ä¸ªgoroutineæ§è¡æ¥æ¶ãç¸åï¼å¦æééæ¯ç©ºçï¼æ¥æ¶ä¼é»å¡ï¼ç´å°å¦ä¸ä¸ªgoroutineæ§è¡åéã
æ没ææè§ï¼å ¶å®ç¼å²ééåéåä¸æ ·ï¼ææä½é½è§£è¦äºã
ååchannelç±»åchan<-intæ¯ä¸ä¸ªåªè½åéçééï¼ç±»å<-chanintæ¯ä¸ä¸ªåªè½æ¥æ¶çééã
ä»»ä½ååééé½å¯ä»¥ç¨ä½ååééï¼ä½åè¿æ¥ä¸è¡ã
è¿æä¸ç¹éè¦æ³¨æï¼closeåªè½ç¨å¨åéééä¸ï¼å¦æç¨å¨æ¥æ¶ééä¼æ¥éã
çä¸ä¸ªååééçä¾åï¼
packagemainimport"fmt"funccounter(outchan<-int){ forx:=0;x<;x++{ out<-x}close(out)}funcsquarer(outchan<-int,in<-chanint){ forv:=rangein{ out<-v*v}close(out)}funcprinter(in<-chanint){ forv:=rangein{ fmt.Println(v)}}funcmain(){ n:=make(chanint)s:=make(chanint)gocounter(n)gosquarer(s,n)printer(s)}syncsyncå æä¾äºä¸¤ç§éç±»åï¼sync.Mutexåsync.RWMutexï¼åè æ¯äºæ¥éï¼åè æ¯è¯»åéã
å½ä¸ä¸ªgoroutineè·åäºMutexåï¼å ¶ä»goroutineä¸ç®¡è¯»åï¼åªè½çå¾ ï¼ç´å°é被éæ¾ã
packagemainimport("fmt""sync""time")funcmain(){ varmutexsync.Mutexwg:=sync.WaitGroup{ }//主goroutineå è·åéfmt.Println("Locking(G0)")mutex.Lock()fmt.Println("locked(G0)")wg.Add(3)fori:=1;i<4;i++{ gofunc(iint){ //ç±äºä¸»goroutineå è·åéï¼ç¨åºå¼å§5ç§ä¼é»å¡å¨è¿éfmt.Printf("Locking(G%d)\n",i)mutex.Lock()fmt.Printf("locked(G%d)\n",i)time.Sleep(time.Second*2)mutex.Unlock()fmt.Printf("unlocked(G%d)\n",i)wg.Done()}(i)}//主goroutine5ç§åéæ¾étime.Sleep(time.Second*5)fmt.Println("readyunlock(G0)")mutex.Unlock()fmt.Println("unlocked(G0)")wg.Wait()}RWMutexå±äºç»å ¸çååå¤è¯»æ¨¡åï¼å½è¯»é被å ç¨æ¶ï¼ä¼é»æ¢åï¼ä½ä¸é»æ¢è¯»ãèåéä¼é»æ¢åå读ã
packagemainimport("fmt""sync""time")funcmain(){ varrwMutexsync.RWMutexwg:=sync.WaitGroup{ }Data:=0wg.Add()fori:=0;i<;i++{ gofunc(tint){ //第ä¸æ¬¡è¿è¡åï¼å解éã//循ç¯å°ç¬¬äºæ¬¡æ¶ï¼è¯»éå®åï¼goroutine没æé»å¡ï¼åæ¶è¯»æåãfmt.Println("Locking")rwMutex.RLock()deferrwMutex.RUnlock()fmt.Printf("Readdata:%v\n",Data)wg.Done()time.Sleep(2*time.Second)}(i)gofunc(tint){ //åéå®ä¸æ¯éè¦è§£éåæè½åçrwMutex.Lock()deferrwMutex.Unlock()Data+=tfmt.Printf("WriteData:%v%d\n",Data,t)wg.Done()time.Sleep(2*time.Second)}(i)}wg.Wait()}æ»ç»å¹¶åç¼ç¨ç®æ¯Goçç¹è²ï¼ä¹æ¯æ ¸å¿åè½ä¹ä¸äºï¼æ¶åçç¥è¯ç¹å ¶å®æ¯é常å¤çï¼æ¬æä¹åªæ¯èµ·å°ä¸ä¸ªæç å¼ççä½ç¨èå·²ã
æ¬æå¼å§ä»ç»äºgoroutineçç®åç¨æ³ï¼ç¶åå¼åºäºééçæ¦å¿µã
ééæä¸ç§ï¼
æ ç¼å²éé
ç¼å²éé
ååéé
æåä»ç»äºGoä¸çéæºå¶ï¼åå«æ¯syncå æä¾çsync.Mutexï¼äºæ¥éï¼åsync.RWMutexï¼è¯»åéï¼ã
goroutineå大精深ï¼åé¢çåè¿æ¯è¦æ ¢æ ¢è¸©çã
æç« ä¸çèå¾åæºç é½ä¸ä¼ å°äºGitHubï¼æéè¦çåå¦å¯èªè¡ä¸è½½ã
å°åï¼github.com/yongxinz/gopher/tree/main/sc
ä½è ï¼yongxinz
golangç½ç»ç¼ç¨(golangç¼ç¨è¯è¨)
Golangç½ç»ç¼ç¨ä¸ç»¸ä¹è·¯-TCP/UDPå°å解æ
TL;DRå¨ä½¿ç¨Golangç¼åTCP/UDPsocketçæ¶åï¼ç¬¬ä¸æ¥åçå°±æ¯å°å解æã
该å½æ°è¿åçå°åå å«çä¿¡æ¯å¦ä¸ï¼
TCPAddréï¼IPæ¢å¯ä»¥æ¯IPv4å°åï¼ä¹å¯ä»¥æ¯IPv6å°åãPortå°±æ¯ç«¯å£äºãZoneæ¯IPv6æ¬å°å°åæå¨çåºåã
ä»è¿åç»æç该å½æ°çåæ°ï¼networkæaddressçç½ç»ç±»åï¼addressæè¦è§£æçå°åï¼ä¼ä»ä¸è§£æåºæ们æ³è¦çIP,PortåZoneã
ä»æºç ä¸å¯ä»¥çåºï¼åæ°networkåªè½æ¯å¦ä¸å个å¼ï¼å¦åä¼å¾å°ä¸ä¸ªé误ã
解æè¿ç¨è·ResolveTCPAddrçä¸æ ·ï¼ä¸è¿å¾å°çæ¯*UDPAddrã
UDPAddrå å«çä¿¡æ¯å¦ä¸ï¼
golangæ¯ä»ä¹ææ
Goè¯è¨(å称Golang)æ¯GoogleçRobertGriesemerï¼RobPikeåKenThompsonå¼åçä¸ç§éæ强类åãç¼è¯åè¯è¨ãGoè¯è¨è¯æ³ä¸Cç¸è¿ï¼ä½åè½ä¸æï¼å åå®å ¨ï¼GC(åå¾åæ¶)ï¼ç»æå½¢æåCSP-style并å计ç®ãæ©å±èµæ
Goè¯è¨ä¸»è¦ç¨ä½æå¡å¨ç«¯å¼åï¼å ¶å®ä½æ¯ç¨æ¥å¼åâ大å软件âçï¼éåäºå¾å¤ç¨åºåä¸èµ·å¼å大å软件ï¼å¹¶ä¸å¼åå¨æé¿ï¼æ¯æäºè®¡ç®çç½ç»æå¡ãGoè¯è¨è½å¤è®©ç¨åºåå¿«éå¼åï¼å¹¶ä¸å¨è½¯ä»¶ä¸æç'å¢é¿è¿ç¨ä¸ï¼å®è½è®©ç¨åºåæ´å®¹æå°è¿è¡ç»´æ¤åä¿®æ¹ãå®èåäºä¼ ç»ç¼è¯åè¯è¨çé«ææ§åèæ¬è¯è¨çæç¨æ§åå¯äºè¡¨è¾¾æ§ã
Goè¯è¨ä½ä¸ºæå¡å¨ç¼ç¨è¯è¨ï¼å¾éåå¤çæ¥å¿ãæ°æ®æå ãèææºå¤çãæ件系ç»ãåå¸å¼ç³»ç»ãæ°æ®åºä»£çç;ç½ç»ç¼ç¨æ¹é¢ï¼Goè¯è¨å¹¿æ³åºç¨äºWebåºç¨ãAPIåºç¨ãä¸è½½åºç¨ç;é¤æ¤ä¹å¤ï¼Goè¯è¨è¿å¯ç¨äºå åæ°æ®åºåäºå¹³å°é¢åï¼ç®åå½å¤å¾å¤äºå¹³å°é½æ¯éç¨Goå¼åã
ä½ä¸ºç¨åºåï¼æ¨èç»åå¦è ç5大ç¼ç¨è¯è¨å ¶å®ï¼åªè¦ä¸æ¯å¤ªå°ä¼ã太边ç¼çç¼ç¨è¯è¨ï¼åªè¦ç²¾éä¸é¨ï¼é½å¯ä»¥æ¨ªè¡ITäºèç½ï¼æ 论就ä¸æåä¸ã
å¨ITç¼ç¨è¿ä¸ªè¡ä¸ï¼åå端åå端ã
å端æå ¥é¨ãæä¸æï¼å¦æä» æ¯ä¸ºäºå°±ä¸èå¦ä¹ ï¼é£ä¹æ¶é´æå ¥äº§åºæ¯ï¼æå¿«çæ¯å¦å端ï¼èä¸æ¯å端ï¼
ä½å¦ä¼äºå端ï¼åå»å¦å端ï¼å°±é常容æï¼å¹¶ä¸å端ä¸ä» å¨å°±ä¸æ¹é¢ï¼èä¸ä»¥åå¼å产åãåä¸é½æ¯å端æä¼å¿ï¼
对äºåãå端è¯è¨ï¼å¦æé½æ¯æ®éçç»ç¨åº¦ï¼ç°é¶æ®µï¼äºè å·¥èµå·®å«ä¸æ¯å¤ªå¤§ï¼ä½ä¸ä¸ªç²¾éå端åä¸ä¸ªç²¾éå端ï¼é½æ¯5年以ä¸çç¨åºåï¼å¾ææ¾ï¼å端ç¨åºåçå·¥èµè¿æ¯å端ç¨åºåå·¥èµé«ã
å 为å¾å¤äººä»äºITç¼ç¨3-5å¹´ï¼é¡¶å¤ä¹å°±ç®çç»ï¼ç§°ä¸ä¸ç²¾éï¼é£ä¹å¯¹äºæ°æï¼è¿çº ç»äºç¼ç¨å¦ä»ä¹è¯è¨å¥½çè¯ï¼æ¨èä¸é¢è¿å ç§è¯è¨æ¥å¦ä¹ ï¼
1ãPHP
å±äºå端è¯è¨ï¼å¦ä¹ å®ç好å¤æ¯ï¼å¦ä¹ æ¶é´çãææ¬ä½ãçææå ¥äº§åºæ¯ææ¾ï¼è½è®©ä½ 对ç¼ç¨ä¸åæææ§æï¼è®©ä½ ç±ä¸ç¼ç¨ï¼å¹¶ä¸å¨å½å é常æµè¡ï¼ç¨æ¥åwebå¼åé常éåï¼è½ååç±»webç³»ç»çå¼åï¼çç»æç²¾éå®ï¼æ 论就ä¸æåä¸ï¼é½å¾easyã缺ç¹æ¯ï¼å ¥é¨å¤ªå®¹æäºï¼å¤ªå¤äººä¼äºï¼åèä¸å¼é±äºï¼æ¾å·¥ä½å®¹æï¼é«èªçè¯ï¼è¦é常精éæè¡ã
2ãjava
ç¸æ¯phpæ¥è¯´ï¼å ¥é¨ç¨å¾®æäºé¾åº¦ï¼ä½çç»æç²¾éåï¼å·¥èµæ®éæ¯phpé«ï¼ä¹å°±æ¯è¯´ä½ æ5å¹´javaå¼åç»éªåæå¹´javaå¼åç»éªï¼æ 论æ¯å·¥èµè¿æ¯ææ¯ï¼æ¯æ天壤ä¹å«çï¼ä½ä½ æ5å¹´phpç»éªåæå¹´phpçç»éªï¼å ¶å®å·®å«ä¸æ¯é常大ãjavaå¯ä»¥åå®åå¼åãæ¡é¢åºç¨ç³»ç»å¼å以åwebå¼åçã
3ãpython
pythonè¯è¨ågolangè¯è¨éå ¶ä¸ä¸ä¸ªæ¥å¦å°±å¯ä»¥ï¼pythonæ¯golangæ´å®¹æäºï¼åºç¨èå´é常广ï¼å¦ï¼webå¼åãç¬è«ã大æ°æ®å¤çãæ¡é¢ç«¯è½¯ä»¶ãè¿å¯ç¨äºæ¸¸æã人工æºè½ãæºå¨äººçãä»å¥½åä»ä¹é½ä¼ï¼ä½ä¸åæä¸é¢åï¼å ¬å¸åèä¼éå ¶ä»è¯è¨ï¼ä»æ¯ä¸ªå¤é¢æï¼ä½å ·ä½é½å¾ç²¾ãå¾ä¸çä¸å¡ï¼åè好å¤å ¬å¸ä¸éä»ï¼è½ç¶å¦æ¤ï¼å¯¹äºä¸ªäººèè¨ï¼å¦ä¹ å®ä¸ä¼éã
4ãgolang
golangä½ä¸ºæå¡å¨ç¼ç¨è¯è¨ï¼å¾éååæ¥å¿å¤çãæ°æ®æå ãèææºå¤çãæ°æ®åºä»£ççå·¥ä½ãå¨ç½ç»ç¼ç¨æ¹é¢ï¼å®è¿å¹¿æ³åºç¨äºwebåºç¨ãAPIåºç¨çé¢åãgolangåå¸äºå¹´ï¼æ¯è¾å¹´è½»ï¼ç®åæå¾å¤æèååä¸åºç¨çéæ±ï¼å·¥èµä¹ä¸éï¼ä½åå¦è ï¼çæå ç¨å®æ¾å·¥ä½æåä¸æé¾åº¦ï¼éåå·²ç»ææ¡äºå ¶ä»è¯è¨çæ åµä¸ï¼å¦ä¹ golangã
5ãC#
éååwindowsç±»æ¡é¢è½¯ä»¶ãåºç¨ç¨åºãwebå¼åï¼BS/CS软件ç¨åºä»é½å¯ä»¥å¼åï¼è½ç¶æ以åå¦è¿asp^^ï¼ä½æ对ä»äºè§£ä¸å¤ï¼ä¸æä¸é¾ï¼ä¹å¯ä»¥å游æå¼åçå端ççã
è¿æè¶ å¤çï¼å¦ï¼Object-CãC++ãCãSwiftãPerl...
对äºå端ï¼åºæ¬ä¸é½æ¯åºäºjavascriptï¼æç®å对å端ä¸æ¯å¾ç²¾éï¼ä½ä¸é¢å 个ä¸ä¸ï¼æ¯é常å¼å¾ä½ å¦ä¹ åææ¡çï¼
1ãvue/uniapp
è¿ä¸¤ä¸ªï¼å¨ç®åï¼å端é常ç«ãå¦è¿ä¸ªå°±ä¸è¦åå»çè¿2个äºï¼reactåangularã
2ãnode.js
è¿ä¸ªæ认为å¯ä»¥è¯´ä»æ¯èæ¬è¯è¨ï¼ä¹å¯ä»¥è¯´ä»æ¯å端è¯è¨ã
3ãH5+CSS+Bootstrap+jquery
è¿ä¸ªé常é常ç容æï¼ä¸è¦ä¸é¨è±æ¶é´å»å¦ï¼å·¥ä½è¿ç¨ä¸ç¨å°ï¼é¡ºä¾¿ççï¼å°±è½ç¨
通过etcd源码学习golang编程——build constraint
在etcd源码中,文件处理部分有方法需区分操作系统,文件路径如下:
文件内容包含TryLockFile和LockFile函数定义,感觉得似C/C++的宏定义,用于跨平台编译。注释中使用 “//go:build”和“// +build”标识,具体用法需探究。
搜索得出,此为Go编程语言的编译约束,通过go help和go help buildconstraint查看帮助文档,官方文档提供了基于该文档的个人总结。
build constraint限定编译内容,类似C/C++宏定义。编译命令示例如下。
官方文档解答:Go1.及前版本使用"// +build",Gofmt命令自动添加"//go:build"约束。老版本使用空格和逗号分隔语法,Gofmt命令能正常转换。
了解GOOS和GOARCH,可通过go tool获取列举。输出对应GOOS/GOARCH。
总结完毕,持续学习!