包含golangbreak的詞條

本文目錄一覽:

php和go語言哪個好

前言

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

常規的方案

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

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

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

存在的問題

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

2、需要封裝大量代碼

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

優化目標

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

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

3、盡量不大量修改代碼

解決方案

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

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

使用雙向管道通信優勢

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

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

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

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

具體實現步驟

1:類庫中的原始調取demo

package main

import (

“fmt”

“github.com/yanyiwu/gojieba”

“strings”

)

func main() {

x := gojieba.NewJieba()

defer x.Free()

s := “小明碩士畢業於中國科學院計算所,後在日本京都大學深造”

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也必須把執行結果返回給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’]中讀數據。

好吧,也許你已經發現,我是標題檔,這裡重點要講的並不只是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源碼中寫的是一個循環,也就是會一直從管道中讀數據。那麼存在一個問題:是不是php進程結束後,Golang的進程還會一直存在?

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

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

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

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

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

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

我正在學習Go語言網絡編程部分,太抽象了有點看不懂啊,哪位大神能夠通俗易懂給我解釋下這個代碼的意思啊

本質上,是作為文件處理的,發送是“write,print”,接受是“read”。

連接相當於打開文件。

為什麼很多程序員不用switch,而是大量的if……else if?

我個人覺得switch其實非常多餘。

1 大部分場景,都是2到3個可能分支,用個if else就可以了,除非有4 個以上分支,太多else顯得不好看,才考慮用switch.

2 switch限制多。switch必須是常量變量。if後面可以寫任意表達式。

3用法複雜,case後面要麼break,要麼return,要是不寫,居然還會繼續執行剩下的分支,對於新手來說分分鐘掉坑。

4 寫法上其實也不比if else優雅簡潔,switch xxx case xxxx ….

所以,switch徒增複雜性,真的不怎麼實用。

如果有10000種switch的可能性,有1000000個值需要被處理,怕是你們說的這些個switch的好處就完全消失了,預期平均每次要比較5000次,1000000個值,總計要比較50億次,不知道你們的CPU是啥主頻能扛得住這個計算量,針對這種情況的終極武器還是hash,根據不同的語言,hash的value可以是匿名函數,可以是接口的不同實現,用hash來快速確定處理算法,而不是switch

答案:主要因為switch不適合業務系統的實際複雜需求,業務不斷的變更迭代,一更改需求,條件的複雜度高了,switch無力處理。

switch優點

那麼什麼時候適合switch,它的場景是:基於單一變量的值(如枚舉),這樣的可讀性比if條件更清晰。

switch缺點

從上面的場景來看,實在太局限,我來簡單說一下它的一些缺點吧:

1. 現實的業務場景很複雜,條件不單一,一旦需求變更,維護代碼相當崩潰。

2. switch經常忘記寫break,估計很多人一不小心就忘記寫了。如果你看過google的代碼規範,你會發現,Google對switch的要求非常多。

switch的封裝才更靈活

其實switch有人還在用也有一部分是 歷史 原因,但是隨着 科技 的發展,原有的設計以及落後了。

有些編程語言,如Python都沒有switch這種語法。當然也有部分新語言Golang和Kotlin還是繼承下來,但是又把switch包裝了一下,去掉了令人誤會的語法,這才讓switch變得靈活起來了。 如果不封裝,很難用。

IF語句的好處

通過上面描述的缺點也就是if語句更靈活的地方,根據業務進行邏輯條件編寫,可維護性高。同時只要寫的代碼質量高,可讀性也就會更高。

建議

現實的業務實際是很複雜的,我也不建議一定要用大量的if……else if,而是應該儘早返回來減少嵌套,這樣增加了可讀性以及降低維護的成本。

從C/ C++來看,當分支較多且switch要比較的值是連續的話,執行速度遠遠遠遠快於if,因為switch是直接跳到目標代碼執行的,而if則需要執行很多條語句,慢的不是一點點,一般編譯器會根據分支數量和比較的值是否連續生成不同彙編代碼,如果編譯器判定不能提升速度的話,switch生成的彙編代碼和if是一模一樣的沒有任何區別。

至於很多人不用switch我覺得可能是:

1.為了方便寫代碼,思維習慣隨手就用if寫了;

2.可能根本就不懂為什麼要用switch吧。

作為程序員來說,我更喜歡switch的結構,更直觀更容易找到相應的代碼塊。不過為什麼很多程序員不用Switch,而是使用大量的if…else if的結構,甚至像Python已經不支持原生Switch語法了?

這個原因很簡單,因為switch語法結構最後編譯還是通過if…else if來完成代碼的,所以從效率角度來說和if…else if一樣的。但是switch對比條件比較單一,絕大多數支持switch的編程語言都支持等於比較,也就是說變量只能等於case中的條件才會執行代碼塊。但是現實情況中,對比條件絕大多數比單一等於運算要複雜得多,因此很多程序員就直接使用if…else if。但是if…else if的結構,後期維護起來會比較不清晰,畢竟沒有Case…Break那麼直觀。但是添加一些註解應該還是能解決這個問題的。

所以,我現在能使用Switch的時候還是會使用switch,畢竟後期代碼維護起來方便點。不過更多時候還是用if…else if。

送大家以下java學習資料

我曾經接手過一份代碼,遇到過一個三十幾個if else套if else的模塊。

心理罵罵咧咧誰他喵寫的這玩意,然後開始review 歷史 。

大致情況是這樣的:第一個程序員寫下這段代碼時,只有兩個if else;後來開始逐漸加需求,先是一個、兩個,隨後量變引起質變,於是邏輯分支快速擴張。

這個時候已經沒有人願意去重構成switch或是其他什麼設計模式了,畢竟複雜度擺在那裡,萬一崩了還得背鍋。

三四個程序員接手這段代碼之後,就變成我現在這種局面了。

第一個程序員絕對沒有料到這麼簡單的邏輯在之後會變成這麼複雜的模塊,甚至在增添第一第二條else時,也只是很隨意的加上。

所以我覺得,這個鍋絕對是是甲方的,讓他娘的隨便改需求。

這麼一想心裡就好受多了,編程嘛,最重要的是要看的開。

於是我又增加了兩條else,測試,提交,下班。

有時候真的不是我們不想寫好代碼,是不能寫好代碼。寫着寫着需求砍了、需求變了,什麼設計模式都不頂用,最終還是怎樣快怎樣方便怎樣來,因為根本沒人知道這段代碼還能不能活的過下一段需求變動。

有的人肯定要說怎麼不訂合同。合同肯定是有的,但是明明白紙黑字寫的合同,該改還是得改,畢竟你要是不同意甲方那些“微小的變動”,以後還做不做了?!金主真能去得罪?

還是要學會得過且過,跟什麼過不去也不能跟自己過不去,糟糕的代碼忍一忍就完了:代碼能跑、頭髮不少,對我們這些打工的人而言比什麼都重要。

現實工作絕不是課本中的理想狀態,會有無數的突發情況在等着你。你定義了半天觀察者、備忘錄,第二天這部分需求被砍了;寫了半天接口,抽象類,忽然下午告訴你要加個十萬八千里打不着邊的啥東西,於是又開始加適配器,等你加完了告訴你又砍了。甚至有次半夜被喊起來改代碼,等改完了發現需求被撤回了,氣的我直接請了兩天假調整心情。

設計模式和大的框架絕對是一個項目中非常重要的東西,但不是絕對重要的;一個好的PM團隊,在某種意義上,才真正決定了這個項目的代碼質量。[1]

請用5秒鐘的時間查看下面的代碼是否存在bug。

OK,熟練的程序猿應該已經發現Bug所在了,在第8行和第10行下面我沒有添加關鍵字break; 這就導致這段代碼的行為邏輯與我的設計初衷不符了。

缺點一. 語法正確,邏輯錯誤

這就是第一個理由為什麼程序猿很少使用switch來做條件判斷,對於新手來說忘記寫break實在是再普通不過了,就算是老猿忘記寫也是時有發生的事情,而這個語法錯誤在諸多的語法檢查器上沒有辦法檢查出來的,因為從語法角度來說是正確的!可是代碼的處理邏輯卻是錯誤的!用if來重寫這段代碼的話,就不會發生這種錯誤。

上面的代碼為了保證正確我添加了else做一個邏輯上的保證,其實如果不寫else,這段代碼也不會發生邏輯錯誤,而且一旦我忘記寫花括號的時候,語法編譯器是會提示我添加的,甚至可以使用eslint這種的工具強制我使用花括號,這樣就不會犯語法錯誤了,一旦出現bug,那麼肯定是我邏輯上的問題了。

缺點二 .死板的語法

switch儘管對於break很寬容,但是對判斷條件很嚴苛,case後面只能跟常量,如果你用C編寫的話,甚至只能用int類型作為判斷條件。對於我們這麼瀟洒自如的程序猿來說,這種限制實在是太麻煩了,用if的話,別說是常量了,我用函數都可以,真正做到方便快捷。

缺點三 .需要子函數來處理分支

這個缺點跟缺點一有關,為了防止漏寫break,因此建議把分支處理方法獨立成一個子函數來處理,這樣在閱讀代碼的時候就會減少忘記寫break帶來的bug,那麼用if來寫的話,我想怎麼寫就怎麼寫,非常隨意自由,但是這也導致了代碼的可讀性大大降低。

switch的優點

既然switch有這麼嚴重的缺點,那怎麼在所有語言中依然會存在呢?那就說下switch的優點吧,它的優點也剛好是它的缺點。

在很久很久以前,那時候的電腦性能還不如一台小霸學習機的時候,聰明的計算機科學家為了提高計算機的處理速度,將一些邏輯分支處理方法簡化了一下,把一些需要做邏輯判斷的操作給固定死,然後只要查表一樣一個一個對一下就能做出相應的反應了。

比如說a=0的判斷,switch和if在cpu上面的處理方式是不一樣的,switch是在編譯階段將子函數的地址和判斷條件綁定了,只要直接將a的直接映射到子函數地址去執行就可以了,但是if處理起來就不一樣了。

它首先要把a的值放到CPU的寄存器中,然後要把比較的值放到CPU的另一個寄存器中,然後做減法,然後根據計算結果跳轉到子函數去執行,這樣一來就要多出3步的操作了,如果邏輯判斷多的話,那麼將會比switch多處許多倍的操作,儘管寄存器操作的速度很快,但是對於當時的學習機來說,這點速度根本不夠用啊。

那還有一個問題,為什麼要使用break來做一個判斷結束呢?這不是很容易造成語法錯誤了?那就要說到子函數的問題上了。

在早起的電腦代碼中是沒有子函數的概念的,那時候都是用goto隨意跳轉的,你想去第10行代碼,很簡單goto 10就可以了。這種編程思維在C的早期階段還是一直受到影響的,因此早期的C也沒有子函數,都是一堆邏輯處理混亂在一起,goto滿天飛,所以那時候你沒有一個最強大腦是寫不了程序的。那為了告訴程序我這裡條件判斷處理結束,就添加了break作為終止符號。後來慢慢的有了子程序,有了更好的編程規範,才一步一步的將寫代碼淪落到體力勞動。

後來發展的新語言為了標榜自己的血統,多少都要參考下C,然後就把switch這種詭異的語法也繼承下來了。但是也不是所有的語言都照搬,比如Google發明的新語言golang和kotlin就又把switch包裝了一下,去掉了令人誤會的語法,又讓switch變得靈活起來了,對了,在代碼重構的時候,還是用switch把,這樣看起來的確代碼更簡潔哦![2]

switch只能用於簡單判斷,不支持表達式。

沒有if else 使用方便。

不是盡量別用,而是不合適沒法用,合適得時候該用還是用。

比如說,變量i要求大於10,小於20,一條if(i10i

go面試題整理(附帶部分自己的解答)

原文:【 】

如果有解答的不對的,麻煩各位在評論寫出來~

go的調度原理是基於GMP模型,G代表一個goroutine,不限制數量;M=machine,代表一個線程,最大1萬,所有G任務還是在M上執行;P=processor代表一個處理器,每一個允許的M都會綁定一個G,默認與邏輯CPU數量相等(通過runtime.GOMAXPROCS(runtime.NumCPU())設置)。

go調用過程:

可以能,也可以不能。

因為go存在不能使用==判斷類型:map、slice,如果struct包含這些類型的字段,則不能比較。

這兩種類型也不能作為map的key。

類似棧操作,後進先出。

因為go的return是一個非原子性操作,比如語句 return i ,實際上分兩步進行,即將i值存入棧中作為返回值,然後執行跳轉,而defer的執行時機正是跳轉前,所以說defer執行時還是有機會操作返回值的。

select的case的表達式必須是一個channel類型,所有case都會被求值,求值順序自上而下,從左至右。如果多個case可以完成,則會隨機執行一個case,如果有default分支,則執行default分支語句。如果連default都沒有,則select語句會一直阻塞,直到至少有一個IO操作可以進行。

break關鍵字可跳出select的執行。

goroutine管理、信息傳遞。context的意思是上下文,在線程、協程中都有這個概念,它指的是程序單元的一個運行狀態、現場、快照,包含。context在多個goroutine中是並發安全的。

應用場景:

例子參考:

waitgroup

channel

len:切片的長度,訪問時間複雜度為O(1),go的slice底層是對數組的引用。

cap:切片的容量,擴容是以這個值為標準。默認擴容是2倍,當達到1024的長度後,按1.25倍。

擴容:每次擴容slice底層都將先分配新的容量的內存空間,再將老的數組拷貝到新的內存空間,因為這個操作不是並發安全的。所以並發進行append操作,讀到內存中的老數組可能為同一個,最終導致append的數據丟失。

共享:slice的底層是對數組的引用,因此如果兩個切片引用了同一個數組片段,就會形成共享底層數組。當sliec發生內存的重新分配(如擴容)時,會對共享進行隔斷。詳細見下面例子:

make([]Type,len,cap)

map的底層是hash table(hmap類型),對key值進行了hash,並將結果的低八位用於確定key/value存在於哪個bucket(bmap類型)。再將高八位與bucket的tophash進行依次比較,確定是否存在。出現hash衝撞時,會通過bucket的overflow指向另一個bucket,形成一個單向鏈表。每個bucket存儲8個鍵值對。

如果要實現map的順序讀取,需要使用一個slice來存儲map的key並按照順序進行排序。

利用map,如果要求並發安全,就用sync.map

要注意下set中的delete函數需要使用 delete(map) 來實現,但是這個並不會釋放內存,除非value也是一個子map。當進行多次delete後,可以使用make來重建map。

使用sync.Map來管理topic,用channel來做隊列。

參考:

多路歸併法:

pre class=”vditor-reset” placeholder=”” contenteditable=”true” spellcheck=”false”p data-block=”0″(1)假設有K路a href=””數據流/a,流內部是有序的,且流間同為升序或降序;

/pp data-block=”0″(2)首先讀取每個流的第一個數,如果已經EOF,pass;

/pp data-block=”0″(3)將有效的k(k可能小於K)個數比較,選出最小的那路mink,輸出,讀取mink的下一個;

/pp data-block=”0″(4)直到所有K路都EOF。

/p/pre

假設文件又1個G,內存只有256M,無法將1個G的文件全部讀到內存進行排序。

第一步:

可以分為10段讀取,每段讀取100M的數據並排序好寫入硬盤。

假設寫入後的文件為A,B,C…10

第二步:

將A,B,C…10的第一個字符拿出來,對這10個字符進行排序,並將結果寫入硬盤,同時記錄被寫入的字符的文件指針P。

第三步:

將剛剛排序好的9個字符再加上從指針P讀取到的P+1位數據進行排序,並寫入硬盤。

重複二、三步驟。

go文件讀寫參考:

保證排序前兩個相等的數其在序列的前後位置順序和排序後它們兩個的前後位置順序相同的排序叫穩定排序。

快速排序、希爾排序、堆排序、直接選擇排序不是穩定的排序算法。

基數排序、冒泡排序、直接插入排序、折半插入排序、歸併排序是穩定的排序算法。

參考:

head只請求頁面的首部。多用來判斷網頁是否被修改和超鏈接的有效性。

get請求頁面信息,並返回實例的主體。

參考:

401:未授權的訪問。

403: 拒絕訪問。

普通的http連接是客戶端連接上服務端,然後結束請求後,由客戶端或者服務端進行http連接的關閉。下次再發送請求的時候,客戶端再發起一個連接,傳送數據,關閉連接。這麼個流程反覆。但是一旦客戶端發送connection:keep-alive頭給服務端,且服務端也接受這個keep-alive的話,兩邊對上暗號,這個連接就可以復用了,一個http處理完之後,另外一個http數據直接從這個連接走了。減少新建和斷開TCP連接的消耗。這個可以在Nginx設置,

這個keepalive_timout時間值意味着:一個http產生的tcp連接在傳送完最後一個響應後,還需要hold住keepalive_timeout秒後,才開始關閉這個連接。

特別注意TCP層的keep alive和http不是一個意思。TCP的是指:tcp連接建立後,如果客戶端很長一段時間不發送消息,當連接很久沒有收到報文,tcp會主動發送一個為空的報文(偵測包)給對方,如果對方收到了並且回復了,證明對方還在。如果對方沒有報文返回,重試多次之後則確認連接丟失,斷開連接。

tcp的keep alive可通過

net.ipv4.tcp_keepalive_intvl = 75 // 當探測沒有確認時,重新發送探測的頻度。缺省是75秒。

net.ipv4.tcp_keepalive_probes = 9 //在認定連接失效之前,發送多少個TCP的keepalive探測包。缺省值是9。這個值乘以tcp_keepalive_intvl之後決定了,一個連接發送了keepalive之後可以有多少時間沒有回應

net.ipv4.tcp_keepalive_time = 7200 //當keepalive起用的時候,TCP發送keepalive消息的頻度。缺省是2小時。一般設置為30分鐘1800

修改:

可以

tcp是面向連接的,upd是無連接狀態的。

udp相比tcp沒有建立連接的過程,所以更快,同時也更安全,不容易被攻擊。upd沒有阻塞控制,因此出現網絡阻塞不會使源主機的發送效率降低。upd支持一對多,多對多等,tcp是點對點傳輸。tcp首部開銷20字節,udp8字節。

udp使用場景:視頻通話、im聊天等。

time-wait表示客戶端等待服務端返回關閉信息的狀態,closed_wait表示服務端得知客戶端想要關閉連接,進入半關閉狀態並返回一段TCP報文。

time-wait作用:

解決辦法:

close_wait:

被動關閉,通常是由於客戶端忘記關閉tcp連接導致。

根據業務來啊~

重要指標是cardinality(不重複數量),這個數量/總行數如果過小(趨近於0)代表索引基本沒意義,比如sex性別這種。

另外查詢不要使用select *,根據select的條件+where條件做組合索引,盡量實現覆蓋索引,避免回表。

殭屍進程:

即子進程先於父進程退出後,子進程的PCB需要其父進程釋放,但是父進程並沒有釋放子進程的PCB,這樣的子進程就稱為殭屍進程,殭屍進程實際上是一個已經死掉的進程。

孤兒進程:

一個父進程退出,而它的一個或多個子進程還在運行,那麼那些子進程將成為孤兒進程。孤兒進程將被init進程(進程號為1)所收養,並由init進程對它們完成狀態收集工作。

子進程死亡需要父進程來處理,那麼意味着正常的進程應該是子進程先於父進程死亡。當父進程先於子進程死亡時,子進程死亡時沒父進程處理,這個死亡的子進程就是孤兒進程。

但孤兒進程與殭屍進程不同的是,由於父進程已經死亡,系統會幫助父進程回收處理孤兒進程。所以孤兒進程實際上是不佔用資源的,因為它終究是被系統回收了。不會像殭屍進程那樣佔用ID,損害運行系統。

原文鏈接:

產生死鎖的四個必要條件:

(1) 互斥條件:一個資源每次只能被一個進程使用。

(2) 請求與保持條件:一個進程因請求資源而阻塞時,對已獲得的資源保持不放。

(3) 不剝奪條件:進程已獲得的資源,在末使用完之前,不能強行剝奪。

(4) 循環等待條件:若干進程之間形成一種頭尾相接的循環等待資源關係。

避免方法:

端口佔用:lsof -i:端口號 或者 nestat

cpu、內存佔用:top

發送信號:kill -l 列出所有信號,然後用 kill [信號變化] [進程號]來執行。如kill -9 453。強制殺死453進程

git log:查看提交記錄

git diff :查看變更記錄

git merge:目標分支改變,而源分支保持原樣。優點:保留提交歷史,保留分支結構。但會有大量的merge記錄

git rebase:將修改拼接到最新,複雜的記錄變得優雅,單個操作變得(revert)很簡單;缺點:

git revert:反做指定版本,會新生成一個版本

git reset:重置到某個版本,中間版本全部丟失

etcd、Consul

pprof

節省空間(非葉子節點不存儲數據,相對b tree的優勢),減少I/O次數(節省的空間全部存指針地址,讓樹變的矮胖),範圍查找方便(相對hash的優勢)。

explain

其他的見:

runtime2.go 中關於 p 的定義: 其中 runnext 指針決定了下一個要運行的 g,根據英文的注釋大致意思是說:

所以當設置 runtime.GOMAXPROCS(1) 時,此時只有一個 P,創建的 g 依次加入 P, 當最後一個即 i==9 時,加入的最後 一個 g 將會繼承當前主 goroutinue 的剩餘時間片繼續執行,所以會先輸出 9, 之後再依次執行 P 隊列中其它的 g。

方法一:

方法二:

[圖片上傳失敗…(image-4ef445-1594976286098)]

方法1:to_days,返回給的日期從0開始算的天數。

方法2:data_add。向日期添加指定時間間隔

[圖片上傳失敗…(image-b67b10-1594976286098)]

go語言為什麼我的程序不會執行子協程?

go的main方法理解為入口函數,程序只執行這一個函數。整個項目由這個函數調度使用。

所以你的協程沒有被運行。

你將協程函數命名,在main函數中調用 go test()即可

GO語言中看到這樣一串代碼,換成java的話怎麼寫??

case QImage::Format_RGB32:

case QImage::Format_ARGB32:

case QImage::Format_ARGB32_Premultiplied:

for(int i = 0; i height; i ++)

{

const QRgb *pSrc = (QRgb *)image.constScanLine(i);

uchar *pDest = (uchar *)ret.scanLine(i);

for( int j = 0; j width; j ++)

{

pDest[j] = qGray(pSrc[j]);

}

}

break;

}

return ret;

}

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/257951.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-15 12:47
下一篇 2024-12-15 12:47

相關推薦

發表回復

登錄後才能評論