成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

go語言數組常用嗎 go數組定義

GO語言學習系列八——GO函數(func)的聲明與使用

GO是編譯性語言,所以函數的順序是無關緊要的,為了方便閱讀,建議入口函數 main 寫在最前面,其余函數按照功能需要進行排列

目前成都創(chuàng)新互聯已為千余家的企業(yè)提供了網站建設、域名、虛擬空間、網站托管運營、企業(yè)網站設計、清徐網站維護等服務,公司將堅持客戶導向、應用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協力一起成長,共同發(fā)展。

GO的函數 不支持嵌套,重載和默認參數

GO的函數 支持 無需聲明變量,可變長度,多返回值,匿名,閉包等

GO的函數用 func 來聲明,且左大括號 { 不能另起一行

一個簡單的示例:

輸出為:

參數:可以傳0個或多個值來供自己用

返回:通過用 return 來進行返回

輸出為:

上面就是一個典型的多參數傳遞與多返回值

對例子的說明:

按值傳遞:是對某個變量進行復制,不能更改原變量的值

引用傳遞:相當于按指針傳遞,可以同時改變原來的值,并且消耗的內存會更少,只有4或8個字節(jié)的消耗

在上例中,返回值 (d int, e int, f int) { 是進行了命名,如果不想命名可以寫成 (int,int,int){ ,返回的結果都是一樣的,但要注意:

當返回了多個值,我們某些變量不想要,或實際用不到,我們可以使用 _ 來補位,例如上例的返回我們可以寫成 d,_,f := test(a,b,c) ,我們不想要中間的返回值,可以以這種形式來舍棄掉

在參數后面以 變量 ... type 這種形式的,我們就要以判斷出這是一個可變長度的參數

輸出為:

在上例中, strs ...string 中, strs 的實際值是b,c,d,e,這就是一個最簡單的傳遞可變長度的參數的例子,更多一些演變的形式,都非常類似

在GO中 defer 關鍵字非常重要,相當于面相對像中的析構函數,也就是在某個函數執(zhí)行完成后,GO會自動這個;

如果在多層循環(huán)中函數里,都定義了 defer ,那么它的執(zhí)行順序是先進后出;

當某個函數出現嚴重錯誤時, defer 也會被調用

輸出為

這是一個最簡單的測試了,當然還有更復雜的調用,比如調試程序時,判斷是哪個函數出了問題,完全可以根據 defer 打印出來的內容來進行判斷,非??焖?,這種留給你們去實現

一個函數在函數體內自己調用自己我們稱之為遞歸函數,在做遞歸調用時,經常會將內存給占滿,這是非常要注意的,常用的比如,快速排序就是用的遞歸調用

本篇重點介紹了GO函數(func)的聲明與使用,下一篇將介紹GO的結構 struct

php和go語言哪個好

前言

最近工作中遇到的一個場景,php項目中需要使用一個第三方的功能,而恰好有一個用Golang寫好的類庫。那么問題就來了,要如何實現不同語言之間的通信呢?下面就來一起看看吧。

常規(guī)的方案

1、 用Golang寫一個http/TCP服務,php通過http/TCP與Golang通信

2、將Golang經過較多封裝,做為php擴展。

3、PHP通過系統命令,調取Golang的可執(zhí)行文件

存在的問題

1、http請求,網絡I/O將會消耗大量時間

2、需要封裝大量代碼

3、PHP每調取一次Golang程序,就需要一次初始化,時間消耗很多

優(yōu)化目標

1、Golang程序只初始化一次(因為初始化很耗時)

2、所有請求不需要走網絡

3、盡量不大量修改代碼

解決方案

1、簡單的Golang封裝,將第三方類庫編譯生成為一個可執(zhí)行文件

2、PHP與Golang通過雙向管道通信

使用雙向管道通信優(yōu)勢

1:只需要對原有Golang類庫進行很少的封裝

2:性能最佳 (IPC通信是進程間通信的最佳途徑)

3:不需要走網絡請求,節(jié)約大量時間

4:程序只需初始化一次,并一直保持在內存中

具體實現步驟

1:類庫中的原始調取demo

package main

import (

"fmt"

"github.com/yanyiwu/gojieba"

"strings"

)

func main() {

x := gojieba.NewJieba()

defer x.Free()

s := "小明碩士畢業(yè)于中國科學院計算所,后在日本京都大學深造"

words := x.CutForSearch(s, true)

fmt.Println(strings.Join(words, "/"))

}

保存文件為main.go,就可以運行

2:調整后代碼為:

package main

import (

"bufio"

"fmt"

"github.com/yanyiwu/gojieba"

"io"

"os"

"strings"

)

func main() {

x := gojieba.NewJieba(

"/data/tmp/jiebaDict/jieba.dict.utf8",

"/data/tmp/jiebaDict/hmm_model.utf8",

"/data/tmp/jiebaDict/user.dict.utf8"

)

defer x.Free()

inputReader := bufio.NewReader(os.Stdin)

for {

s, err := inputReader.ReadString('\n')

if err != nil err == io.EOF {

break

}

s = strings.TrimSpace(s)

if s != "" {

words := x.CutForSearch(s, true)

fmt.Println(strings.Join(words, " "))

} else {

fmt.Println("get empty \n")

}

}

}

只需要簡單的幾行調整,即可實現:從標準輸入接收字符串,經過分詞再輸出

測試:

# go build test

# ./test

# //等待用戶輸入,輸入”這是一個測試“

# 這是 一個 測試 //程序

3:使用cat與Golang通信做簡單測試

//準備一個title.txt,每行是一句文本

# cat title.txt | ./test

正常輸出,表示cat已經可以和Golang正常交互了

4:PHP與Golang通信

以上所示的cat與Golang通信,使用的是單向管道。即:只能從cat向Golang傳入數據,Golang輸出的數據并沒有傳回給cat,而是直接輸出到屏幕。但文中的需求是:php與Golang通信。即php要傳數據給Golang,同時Golang也必須把執(zhí)行結果返回給php。因此,需要引入雙向管道。

在PHP中管道的使用:popen("/path/test") ,具體就不展開說了,因為此方法解決不了文中的問題。

雙向管道:

$descriptorspec = array(

0 = array("pipe", "r"),

1 = array("pipe", "w")

);

$handle = proc_open(

'/webroot/go/src/test/test',

$descriptorspec,

$pipes

);

fwrite($pipes['0'], "這是一個測試文本\n");

echo fgets($pipes[1]);

解釋:使用proc_open打開一個進程,調用Golang程序。同時返回一個雙向管道pipes數組,php向$pipe['0']中寫數據,從$pipe['1']中讀數據。

好吧,也許你已經發(fā)現,我是標題檔,這里重點要講的并不只是PHP與Golang如何通信。而是在介紹一種方法: 通過雙向管道讓任意語言通信。(所有語言都會實現管道相關內容)

測試:

通過對比測試,計算出各個流程占用的時間。下面提到的title.txt文件,包含100萬行文本,每行文本是從b2b平臺取的商品標題

1: 整體流程耗時

time cat title.txt | ./test /dev/null

耗時:14.819秒,消耗時間包含:

進程cat讀出文本

通過管道將數據傳入Golang

Golang處理數據,將結果返回到屏幕

2:計算分詞函數耗時。方案:去除分詞函數的調取,即:注釋掉Golang源代碼中的調取分詞那行的代碼

time cat title.txt | ./test /dev/null

耗時:1.817秒時間,消耗時間包含:

進程cat讀出文本

通過管道將數據傳入Golang

Golang處理數據,將結果返回到屏幕

分詞耗時 = (第一步耗時) - (以上命令所耗時)

分詞耗時 : 14.819 - 1.817 = 13.002秒

3:測試cat進程與Golang進程之間通信所占時間

time cat title.txt /dev/null

耗時:0.015秒,消耗時間包含:

進程cat讀出文本

通過管道將數據傳入Golang

go處理數據,將結果返回到屏幕

管道通信耗時:(第二步耗時) - (第三步耗時)

管道通信耗時: 1.817 - 0.015 = 1.802秒

4:PHP與Golang通信的時間消耗

編寫簡單的php文件:

?php

$descriptorspec = array(

0 = array("pipe", "r"),

1 = array("pipe", "w")

);

$handle = proc_open(

'/webroot/go/src/test/test',

$descriptorspec,

$pipes

);

$fp = fopen("title.txt", "rb");

while (!feof($fp)) {

fwrite($pipes['0'], trim(fgets($fp))."\n");

echo fgets($pipes[1]);

}

fclose($pipes['0']);

fclose($pipes['1']);

proc_close($handle);

流程與上面基本一致,讀出title.txt內容,通過雙向管道傳入Golang進程分詞后,再返回給php (比上面的測試多一步:數據再通過管道返回)

time php popen.php /dev/null

耗時:24.037秒,消耗時間包含:

進程PHP讀出文本

通過管道將數據傳入Golang

Golang處理數據

Golang將返回結果再寫入管道,PHP通過管道接收數據

將結果返回到屏幕

結論:

1 :整個分詞過程中的耗時分布

使用cat控制邏輯耗時: 14.819 秒

使用PHP控制邏輯耗時: 24.037 秒(比cat多一次管道通信)

單向管道通信耗時: 1.8 秒

Golang中的分詞函數耗時: 13.002 秒

2:分詞函數的性能: 單進程,100萬商品標題分詞,耗時13秒

以上時間只包括分詞時間,不包括詞典載入時間。但在本方案中,詞典只載入一次,所以載入詞典時間可以忽略(1秒左右)

3:PHP比cat慢 (這結論有點多余了,呵呵)

語言層面慢: (24.037 - 1.8 - 14.819) / 14.819 = 50%

單進程對比測試的話,應該不會有哪個語言比cat更快。

相關問題:

1:以上Golang源碼中寫的是一個循環(huán),也就是會一直從管道中讀數據。那么存在一個問題:是不是php進程結束后,Golang的進程還會一直存在?

管道機制自身可解決此問題。管道提供兩個接口:讀、寫。當寫進程結束或者意外掛掉時,讀進程也會報錯,以上Golang源代碼中的err邏輯就會執(zhí)行,Golang進程結束。

但如果PHP進程沒有結束,只是暫時沒有數據傳入,此時Golang進程會一直等待。直到php結束后,Golang進程才會自動結束。

2:能否多個php進程并行讀寫同一個管道,Golang進程同時為其服務?

不可以。管道是單向的,如果多個進程同時向管道中寫,那Golang的返回值就會錯亂。

可以多開幾個Golang進程實現,每個php進程對應一個Golang進程。

最后,上面都是瞎扯的。如果你了解管道、雙向管道,上面的解釋對你基本沒啥用。但如果你不了解管道,調試上面的代碼沒問題,但稍有修改就有可能掉坑里。

Go語言編程入門時需要注意什么

剛入門Go語言小白需要注意以下五點:

1、注意書寫代碼的一些規(guī)范吧,特別是注意大小寫、英文標點符號區(qū)別等,在特別的位置寫上注釋。

2、主要是理解偽代碼所描述的算法,偽代碼要注意是不能直接運行的。

3、注意編譯器版本與書籍上所介紹版本是否一致,也注意特殊符號,印刷版本可能與實際不一致。

4、書上的版本和當前所用的版本是否一致,有些情況下書上版本在現在來用已經過時了。

5、邏輯走通;給自己信心,其實起步階段不難的。

Go語言中恰到好處的內存對齊

在開始之前,希望你計算一下 Part1 共占用的大小是多少呢?

輸出結果:

這么一算, Part1 這一個結構體的占用內存大小為 1+4+1+8+1 = 15 個字節(jié)。相信有的小伙伴是這么算的,看上去也沒什么毛病

真實情況是怎么樣的呢?我們實際調用看看,如下:

輸出結果:

最終輸出為占用 32 個字節(jié)。這與前面所預期的結果完全不一樣。這充分地說明了先前的計算方式是錯誤的。為什么呢?

在這里要提到 “內存對齊” 這一概念,才能夠用正確的姿勢去計算,接下來我們詳細的講講它是什么

有的小伙伴可能會認為內存讀取,就是一個簡單的字節(jié)數組擺放

上圖表示一個坑一個蘿卜的內存讀取方式。但實際上 CPU 并不會以一個一個字節(jié)去讀取和寫入內存。相反 CPU 讀取內存是 一塊一塊讀取 的,塊的大小可以為 2、4、6、8、16 字節(jié)等大小。塊大小我們稱其為 內存訪問粒度 。如下圖:

在樣例中,假設訪問粒度為 4。 CPU 是以每 4 個字節(jié)大小的訪問粒度去讀取和寫入內存的。這才是正確的姿勢

另外作為一個工程師,你也很有必要學習這塊知識點哦 :)

在上圖中,假設從 Index 1 開始讀取,將會出現很崩潰的問題。因為它的內存訪問邊界是不對齊的。因此 CPU 會做一些額外的處理工作。如下:

從上述流程可得出,不做 “內存對齊” 是一件有點 "麻煩" 的事。因為它會增加許多耗費時間的動作

而假設做了內存對齊,從 Index 0 開始讀取 4 個字節(jié),只需要讀取一次,也不需要額外的運算。這顯然高效很多,是標準的 空間換時間 做法

在不同平臺上的編譯器都有自己默認的 “對齊系數”,可通過預編譯命令 #pragma pack(n) 進行變更,n 就是代指 “對齊系數”。一般來講,我們常用的平臺的系數如下:

另外要注意,不同硬件平臺占用的大小和對齊值都可能是不一樣的。因此本文的值不是唯一的,調試的時候需按本機的實際情況考慮

輸出結果:

在 Go 中可以調用 unsafe.Alignof 來返回相應類型的對齊系數。通過觀察輸出結果,可得知基本都是 2^n ,最大也不會超過 8。這是因為我手提(64 位)編譯器默認對齊系數是 8,因此最大值不會超過這個數

在上小節(jié)中,提到了結構體中的成員變量要做字節(jié)對齊。那么想當然身為最終結果的結構體,也是需要做字節(jié)對齊的

接下來我們一起分析一下,“它” 到底經歷了些什么,影響了 “預期” 結果

在每個成員變量進行對齊后,根據規(guī)則 2,整個結構體本身也要進行字節(jié)對齊,因為可發(fā)現它可能并不是 2^n ,不是偶數倍。顯然不符合對齊的規(guī)則

根據規(guī)則 2,可得出對齊值為 8?,F在的偏移量為 25,不是 8 的整倍數。因此確定偏移量為 32。對結構體進行對齊

Part1 內存布局:axxx|bbbb|cxxx|xxxx|dddd|dddd|exxx|xxxx

通過本節(jié)的分析,可得知先前的 “推算” 為什么錯誤?

是因為實際內存管理并非 “一個蘿卜一個坑” 的思想。而是一塊一塊。通過空間換時間(效率)的思想來完成這塊讀取、寫入。另外也需要兼顧不同平臺的內存操作情況

在上一小節(jié),可得知根據成員變量的類型不同,其結構體的內存會產生對齊等動作。那假設字段順序不同,會不會有什么變化呢?我們一起來試試吧 :-)

輸出結果:

通過結果可以驚喜的發(fā)現,只是 “簡單” 對成員變量的字段順序進行改變,就改變了結構體占用大小

接下來我們一起剖析一下 Part2 ,看看它的內部到底和上一位之間有什么區(qū)別,才導致了這樣的結果?

符合規(guī)則 2,不需要額外對齊

Part2 內存布局:ecax|bbbb|dddd|dddd

通過對比 Part1 和 Part2 的內存布局,你會發(fā)現兩者有很大的不同。如下:

仔細一看, Part1 存在許多 Padding。顯然它占據了不少空間,那么 Padding 是怎么出現的呢?

通過本文的介紹,可得知是由于不同類型導致需要進行字節(jié)對齊,以此保證內存的訪問邊界

那么也不難理解,為什么 調整結構體內成員變量的字段順序 就能達到縮小結構體占用大小的疑問了,是因為巧妙地減少了 Padding 的存在。讓它們更 “緊湊” 了。這一點對于加深 Go 的內存布局印象和大對象的優(yōu)化非常有幫

如何看待go語言泛型的最新設計?

Go 由于不支持泛型而臭名昭著,但最近,泛型已接近成為現實。Go 團隊實施了一個看起來比較穩(wěn)定的設計草案,并且正以源到源翻譯器原型的形式獲得關注。本文講述的是泛型的最新設計,以及如何自己嘗試泛型。

例子

FIFO Stack

假設你要創(chuàng)建一個先進先出堆棧。沒有泛型,你可能會這樣實現:

type?Stack?[]interface{}func?(s?Stack)?Peek()?interface{}?{

return?s[len(s)-1]

}

func?(s?*Stack)?Pop()?{

*s?=?(*s)[:

len(*s)-1]

}

func?(s?*Stack)?Push(value?interface{})?{

*s?=?

append(*s,?value)

}

但是,這里存在一個問題:每當你 Peek 項時,都必須使用類型斷言將其從 interface{} 轉換為你需要的類型。如果你的堆棧是 *MyObject 的堆棧,則意味著很多 s.Peek().(*MyObject)這樣的代碼。這不僅讓人眼花繚亂,而且還可能引發(fā)錯誤。比如忘記 * 怎么辦?或者如果您輸入錯誤的類型怎么辦?s.Push(MyObject{})` 可以順利編譯,而且你可能不會發(fā)現到自己的錯誤,直到它影響到你的整個服務為止。

通常,使用 interface{} 是相對危險的。使用更多受限制的類型總是更安全,因為可以在編譯時而不是運行時發(fā)現問題。

泛型通過允許類型具有類型參數來解決此問題:

type?Stack(type?T)?[]Tfunc?(s?Stack(T))?Peek()?T?{

return?s[len(s)-1]

}

func?(s?*Stack(T))?Pop()?{

*s?=?(*s)[:

len(*s)-1]

}

func?(s?*Stack(T))?Push(value?T)?{

*s?=?

append(*s,?value)

}

這會向 Stack 添加一個類型參數,從而完全不需要 interface{}?,F在,當你使用 Peek() 時,返回的值已經是原始類型,并且沒有機會返回錯誤的值類型。這種方式更安全,更容易使用。(譯注:就是看起來更丑陋,^-^)

此外,泛型代碼通常更易于編譯器優(yōu)化,從而獲得更好的性能(以二進制大小為代價)。如果我們對上面的非泛型代碼和泛型代碼進行基準測試,我們可以看到區(qū)別:

type?MyObject?struct?{

X?

int

}

var?sink?MyObjectfunc?BenchmarkGo1(b?*testing.B)?{

for?i?:=?0;?i??b.N;?i++?{

var?s?Stack

s.Push(MyObject{})

s.Push(MyObject{})

s.Pop()

sink?=?s.Peek().(MyObject)

}

}

func?BenchmarkGo2(b?*testing.B)?{

for?i?:=?0;?i??b.N;?i++?{

var?s?Stack(MyObject)

s.Push(MyObject{})

s.Push(MyObject{})

s.Pop()

sink?=?s.Peek()

}

}

結果:

BenchmarkGo1BenchmarkGo1-16?????12837528?????????87.0?ns/op???????48?B/op????????2?allocs/opBenchmarkGo2BenchmarkGo2-16?????28406479?????????41.9?ns/op???????24?B/op????????2?allocs/op

在這種情況下,我們分配更少的內存,同時泛型的速度是非泛型的兩倍。

合約(Contracts)

上面的堆棧示例適用于任何類型。但是,在許多情況下,你需要編寫僅適用于具有某些特征的類型的代碼。例如,你可能希望堆棧要求類型實現 String() 函數

go語言數組int如何轉int?

有兩種方法,根據例子說明: String - ints="12345";int i;第一種方法:i=Integer.parseInt(s);第二種方法:i=Integer.valueOf(s).intValue();第一種方法:i=Integer.parseInt(s);//直接使用靜態(tài)方法,不會產生多余的對象,但會拋出異常第二種.

名稱欄目:go語言數組常用嗎 go數組定義
地址分享:http://jinyejixie.com/article10/dosoogo.html

成都網站建設公司_創(chuàng)新互聯,為您提供網站策劃、用戶體驗手機網站建設、品牌網站設計動態(tài)網站、靜態(tài)網站

廣告

聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯

h5響應式網站建設
临城县| 弥勒县| 秀山| 高台县| 营口市| 洪湖市| 津南区| 开原市| 开远市| 桑植县| 花垣县| 花垣县| 上杭县| 漠河县| 汝阳县| 齐齐哈尔市| 新邵县| 芜湖市| 交口县| 太仓市| 河间市| 勐海县| 永吉县| 石阡县| 青浦区| 汶川县| 海门市| 夹江县| 阿尔山市| 尉犁县| 克东县| 西乌珠穆沁旗| 达拉特旗| 土默特右旗| 方城县| 水城县| 交城县| 昌黎县| 天镇县| 玉田县| 丰宁|