1. 程式人生 > >專注於網路程式設計,遊戲後臺,高併發

專注於網路程式設計,遊戲後臺,高併發

go語言天生支援高併發,同時訪問幾千幾萬網頁不是問題。例如在寫網路爬蟲時,我們從根頁面找出其他的頁面,然後其他的頁面又找出其他的頁面,如此反覆。雖然go可以支援同時訪問那麼多頁面,但是作業系統卻不支援同時開啟那麼多頁面,因為每次訪問頁面都是一次socket通訊。每次socket通訊就會佔用檔案描述符fd,作業系統同時支援開啟的fd是有限制的。所以有必要做併發控制。

下面模擬爬蟲的實驗。有一個函式每次隨機產生0-30個int型陣列。對陣列遍歷時又根據那個函式產生隨機陣列。我們先看看不做併發控制的程式碼:

package main 

import (
    "fmt"
    "time"
    "math/rand"
    "sync/atomic"
)

var Sum int32 = 0      //當前開啟fd的總量

func produceInt() []int {
    defer func()  {
        atomic.AddInt32(&Sum, -1)
    }()
    
    atomic.AddInt32(&Sum, 1)
    rnd := rand.Intn(30)            //這次產生的int的數量
    var list []int
    for i := 0; i < rnd; i++  {
        list = append(list, rand.Intn(100))
    }
    time.Sleep(time.Millisecond * 100)
    return list
}

func main()  {
    workList := make(chan []int)

    go func()  {
        workList <- []int{1}
    }()

    go func()  {
        for {
            fmt.Println("\nsum is ", Sum)      //列印當前fd的數量
            time.Sleep(time.Second)
        }
    }()

    for list := range workList  {     //list仍然是個[]int
        for range list  {
            go func()  {
                workList <- produceInt()
            }()
        }
    }
} 

運行當前的程式碼,發現fd是一直不停的在增加的。我們開始想辦法控制併發。
最簡單的方法就是利用chan來實現:

package main 

import (
    "fmt"
    "time"
    "math/rand"
    "sync/atomic"
)

var Sum int32 = 0      //當前開啟fd的總量

var tokens = make(chan struct{}, 30)

func produceInt() []int {
    defer func()  {
        atomic.AddInt32(&Sum, -1)
    }()
    
    tokens <- struct{}{}            //用chan同步來控制
    atomic.AddInt32(&Sum, 1)    
    rnd := rand.Intn(30)            //這次產生的int的數量
    var list []int
    for i := 0; i < rnd; i++  {
        list = append(list, rand.Intn(100))
    }
    time.Sleep(time.Millisecond * 100)
    <- tokens
    return list
}

func main()  {
    workList := make(chan []int)

    go func()  {
        workList <- []int{1}
    }()

    go func()  {
        for {
            fmt.Println("\nsum is ", Sum)      //列印當前fd的數量
            time.Sleep(time.Second)
        }
    }()

    for list := range workList  {     //list仍然是個[]int
        for range list  {
            go func()  {
                workList <- produceInt()
            }()
        }
    }
} 

另外一種寫法就是,利用chan,每次只取陣列元素中的一個。然後開啟N個這樣的協程,程式碼如下:

package main 

import (
    "fmt"
    "time"
    "math/rand"
    "sync/atomic"
    "runtime"
)

var Sum int32 = 0      //當前開啟fd的總量

func produceInt() []int {
    defer func()  {
        atomic.AddInt32(&Sum, -1)
    }()
    
    atomic.AddInt32(&Sum, 1)
    rnd := rand.Intn(30)            //這次產生的int的數量
    var list []int
    for i := 0; i < rnd; i++  {
        list = append(list, rand.Intn(100))
    }
    time.Sleep(time.Millisecond * 100)
    return list
}

func main()  {
    workList := make(chan []int)
    unseen := make(chan int)

    go func()  {
        for {
            fmt.Printf("sum is %d", Sum)      //列印當前fd的數量
            fmt.Printf("num of co is %d\n", runtime.NumGoroutine())      //當前協程的數量
            time.Sleep(time.Second)
        }
    }()

    go func()  {
        workList <- []int{1}
    }()

    for i := 0; i < 20; i++  {
        go func()  {
            for range unseen  {
                k := produceInt()
                go func()  {
                    workList <- k
                }()
            }
        }()
    }

    for list := range workList  {
        for _, l := range list  {
            unseen <- l
        }
    }
} 

 注意,雖然併發得到了控制,但是協程的數量是一直在增加的,執行第三個程式碼就可以看。

相關推薦

專注網路程式設計,遊戲後臺,併發

go語言天生支援高併發,同時訪問幾千幾萬網頁不是問題。例如在寫網路爬蟲時,我們從根頁面找出其他的頁面,然後其他的頁面又找出其他的頁面,如此反覆。雖然go可以支援同時訪問那麼多頁面,但是作業系統卻不支援同時開啟那麼多頁面,因為每次訪問頁面都是一次socket通訊。每次socke

Linux學習之網路程式設計(多程序併發伺服器)

言之者無罪,聞之者足以戒。 - “詩序” 上面我們所說過的通訊都是一個伺服器一個客戶端之間的通訊,下面我們來交流一下多程序併發伺服器的相關知識 邏輯上就是這個樣子的,就是一個伺服器多個客戶端進行資料的傳輸。 1、傳送資料的函式: ssize_t send(int sockfd,

linux網路程式設計之多程序併發伺服器

1)使用多程序併發伺服器考慮的因素:       (1)父程序描述最大檔案描述符的個數(父程序需要關閉accept返回的新檔案描述符)       (2)系統內可建立程序的個數(與記憶體大小相關)       (3)程序建立過多是否降低整體服務效能 2)多程序建立併發

嵌入式Linux網路程式設計,TCP多併發伺服器,TCP多執行緒併發伺服器,TCP多程序併發伺服器

文章目錄 1,TCP多執行緒併發伺服器 1.1,標頭檔案net.h 1.2,客戶端client.c 1.3,伺服器端server.c 2,TCP多程序併發伺服器 2.1,標頭檔案net.h 2.2,客

Java併發程式設計入門與併發面試

第6章 J.U.C之AQS講解 AQS是J.U.C的重要元件,也是面試的重要考點。這一章裡將重點講解AQS模型設計及相關同步元件的原理和使用,都非常實用,具體包括:CountDownLatch、Semaphore、CyclicBarrier、ReentrantLock與鎖、Condition等。這些元

flylkly的小窩[專注網路安全]

若一臺計算機的字長為32位,則表明該計算機  (  ) A : 能處理的數值最大為4位十進位制數 B : 能處理的數值最多為4個位元組 C : 在CPU中能夠作為一個整體加以處理的二進位制資料為4個位元組 D : CPU中運算的結果最大為232 答案是C 解說: 字長是指微

非同步程式設計CompletableFuture實現併發系統優化之請求合併

  先說場景:   根據Redis官網介紹,單機版Redis的讀寫效能是12萬/秒,批量處理可以達到70萬/秒。不管是快取或者是資料庫,都有批量處理的功能。當我們的系統達到瓶頸的時候,我們考慮充分的壓榨快取和資料庫的效能,應對更大的併發請求。適用於電商促銷雙十一,等特定高併發的場景,讓系統可以支撐更高的併發

linux 併發網路程式設計之epoll詳解

前言       I/O多路複用有很多種實現。在linux上,2.4核心前主要是select和poll,自Linux 2.6核心正式引入epoll以來,epoll已經成為了目前實現高效能網路伺服器的必備技術。儘管他們的使用方法不盡相同,但是本質上卻沒有什麼區別。本文將重點探

Python併發網路程式設計庫:eventlet

eventlet是一個用來處理和網路相關的python庫函式,而且可以通過協程來實現併發,在eventlet裡,把“協程”叫做 greenthread(綠色執行緒)。所謂併發,就是開啟了多個greenthread,並且對這些greenthread進行管理,以實現非阻塞式的

Linux IO多路複用之epoll網路程式設計併發的使用例子 (含原始碼)

#include <unistd.h> #include <sys/types.h> /* basic system data types */ #include <sys/socket.h> /* basic socket definiti

HttpClient客戶端網路程式設計——可用、併發

  本文是HttpClient的學習部落格,RestTemplate是基於HttpClient的封裝,feign可基於HttpClient進行網路通訊。   那麼作為較底層的客戶端網路程式設計框架,該怎麼配置使其能高可用,高併發,可支援Https協議呢?通讀本文也許你會有答案或者啟發。   本文是Maven專

實戰Java併發程式設計.epub

    【下載地址】 在過去單核CPU時代,單任務在一個時間點只能執行單一程式,隨著多核CPU的發展,並行程式開發就顯得尤為重要。 《實戰Java高併發程式設計》主要介紹基於Java的並行程式設計基礎、思路、方法和實戰。第一,立足於併發程式基礎,詳細介紹Ja

併發程式設計:同步類容器的問題

同步容器類存在的問題 同步類容器都是執行緒安全的,但在某些場景下可能需要加鎖來保護複合操作,在複合操作,如:迭代、跳轉已經條件運算中,這些操作可能會表現出意外的行為,最經典的便是ConcurrentModificationException,原因是當容器迭代的過程中,被併發的修改了內

併發程式設計併發Queue介面

佇列是一種先進先出或者後進後出的資料結構。在此我們模擬一下佇列這種資料結構: MyQueue.java定義如下: public class MyQueue { //佇列的容器 private LinkedList<Object> list = new L

併發程式設計:初識併發容器類

JDK5.0以後提供了多種併發類容器來替代同步容器類從而改善效能。同步類容器狀態都是序列化的。他們雖然實現了執行緒安全,但是嚴重降低了併發性,在多執行緒環境時,嚴重降低了應用程式的吞吐量。 ConcurrentMap介面 ConcurrentMap介面有兩個重要的實現類:Conc

併發程式設計:執行緒安全和ThreadLocal

執行緒安全的概念:當多個執行緒訪問某一個類(物件或方法)時,這個類始終都能表現出正確的行為,那麼這個類(物件或方法)就是執行緒安全的。 執行緒安全 說的可能比較抽象,下面就以一個簡單的例子來看看什麼是執行緒安全問題。 public class MyThread impleme

2018最新實戰Java併發程式設計

在過去單核CPU時代,單任務在一個時間點只能執行單一程式,隨著多核CPU的發展,並行程式開發就顯得尤為重要。《實戰Java高併發程式設計》主要介紹基於Java的並行程式設計基礎、思路、方法和實戰。第一,立足於併發程式基礎,詳細介紹Java中進行並行程式設計的基本方法。第二,進一步詳細介紹JDK中對並

淺談併發程式設計

1、首先考慮分散式,業務功能服務化         使用阿里的dubbo框架,使用zookeeper作為註冊中心;或者spring cloud等;系統靈活部署,在真正消耗資源的服務上,考慮增加例項。 2、打薄閘道器層     &

併發程式設計 volatile 和 加鎖 解決快取不一致

因為程式執行都在cpu中,但是如果沒有快取記憶體,cpu大部分的時間都用來了讀取記憶體的資料。 從而Cpu有 快取記憶體,在執行指令前,會把相關需要的資料提前拷貝到cpu,運算完成後在刷回記憶體裡。   快取記憶體主要提前快取資料到cpu,等cpu運算完成後把結果返回給主存

仿微信 IM後臺(億級流量併發) 瘋狂實戰

仿微信 億級流量 IM後臺 實戰 分散式、高併發、億級流量—— 瘋狂創客圈 死磕Netty 系列之10 億級流量IM的應用場景 隨著移動網際網路、AI的飛速發展,高效能高併發IM(即時通訊),有著非常廣泛的應用場景。 一切高實