Coprocess swoole vs. golang

  • COOPERATION CONCEPT Coroutines are a lighter existence than threads, just as a process can have multiple threads, a thread can have multiple threads. A collaboration has the following characteristics
  1. User-state execution, completely controlled by the program, not managed by the operating system kernel
  2. Suitable for handling IO-intensive tasks, not detailed here as to what IO-intensive tasks are, mainly different from CPU-intensive tasks
  3. Turn competing resources in threads into collaborative runs
  4. Channel mode for inter-protocol communication
  5. A small amount of context switching overhead, mainly running on the thread, comparing the process's context switching is saved in the stack resources, while the collaboration is asynchronous and non-blocking, which is equivalent to queued tasks in user-mode threads. It only needs channel as a callback and does not need to grab resources twice after the task is completed.

Swoole Protocol

Single-process model, relatively simple to implement/lock-free/high performance, single-threaded, unable to utilize CPU multi-core, running in user process

echo "main start\n";

  • go(function () {

  • echo "coro ".co::getcid()." start\n";
    
  • co::sleep(.1);
    
  • echo "coro ".co::getcid()." end\n";
    
  • });

  • echo "main flag\n";

  • go(function () {

  • echo "coro ".co::getcid()." start\n";
    
  • co::sleep(.1);
    
  • echo "coro ".co::getcid()." end\n";
    
  • });

  • echo "end\n";

Golang Protocol

The MPG model runs on the operating system kernel CPU, so you can take advantage of the CPU multicore M: Represents a kernel-level thread, where an M is a thread and goroutine runs on top of M. G: Represents a goroutine that has its own stack. P: The full name is Processor, Processor.It mainly executes a goroutine, and it also maintains a goroutine queue.

The native level of the Go language supports co-layers without requiring the declaration of a collaboration environment. Here's another famous sentence To communicate through shared memory, instead, share memory through communication

  • package main

  • import (

  • "fmt"
    
  • "sync"
    
  • "math/rand"
    
  • "container/ring"
    
  • "strings"
    
  • "time"
    
  • )

  • var (

  • wg             sync.WaitGroup // For goroutine count
    
  • times          = 2  // Serves per player
    
  • nums           = 4  // How many players
    
  • serveTotals    = nums * times  // Total number of serves
    
  • score_balls_A  = make([]TableTennis, 0, serveTotals) // A's Score Ball
    
  • score_balls_B  = make([]TableTennis, 0, serveTotals) // B's Score Ball
    
  • turn           = ring.New(4)                         // Serving sequence
    
  • serveMetux     sync.Mutex                            // Serving lock
    
  • catch_chanel_B = make(chan TableTennis, 0)           // Channel for Team B to catch the ball
    
  • catch_chanel_A = make(chan TableTennis, 0)           // A Team's Catching Channel
    
  • balls_ids      = make(chan int, serveTotals)         // id of the ball
    
  • )

  • //Table tennis

  • type TableTennis struct {

  • id    int
    
  • trail string // The track of the ball
    
  • }

  • func serve() {

  • defer wg.Done()
    
  • //Initialize the serving order
    
  • turn.Value = "A1"
    
  • turn = turn.Next()
    
  • turn.Value = "B1"
    
  • turn = turn.Next()
    
  • turn.Value = "A2"
    
  • turn = turn.Next()
    
  • turn.Value = "B2"
    
  • //Start serving
    
  • for i := 0; i < times; i++ {
    
  •     for j := 0; j < nums; j++ {
    
  •         serveMetux.Lock() // Next ball when unlocking
    
  •         turn = turn.Next()
    
  •         name := turn.Value.(string)
    
  •         t := TableTennis{<-balls_ids, name + "-in"}
    
  •         if name[0] == 'A' {
    
  •             catch_chanel_B <- t
    
  •         } else {
    
  •             catch_chanel_A <- t
    
  •         }
    
  •     }
    
  • }
    
  • time.Sleep(time.Second)  // Wait for player goroutine to catch_Use of Chanel
    
  • close(catch_chanel_A)
    
  • close(catch_chanel_B)
    
  • }

  • // Team A Player

  • func playerA(name string, rate int) {

  • defer wg.Done() // Delay Decreasing Count
    
  • for t := range catch_chanel_A {
    
  •     // 2. Hit the ball
    
  •     rest := shot(rate)
    
  •     // 3. Record the track of the ball
    
  •     t.trail += "-" + name + "-" + rest
    
  •     //Ball out of bounds
    
  •     if strings.Compare("out", rest) == 0 {
    
  •         //Opposite Score
    
  •         score_balls_B = append(score_balls_B, t)
    
  •         fmt.Println(t)
    
  •         serveMetux.Unlock()
    
  •         continue
    
  •     }
    
  •     // 4. Prepare to catch the ball from the opposite team
    
  •     catch_chanel_B <- t
    
  • }
    
  • }

  • // Team B Player

  • func playerB(name string, rate int) {

  • defer wg.Done() // Delay Decreasing Count
    
  • for t := range catch_chanel_B {
    
  •     // 2. Hit the ball
    
  •     rest := shot(rate)
    
  •     // 3. Record the track of the ball
    
  •     t.trail += "-" + name + "-" + rest
    
  •     //Ball out of bounds
    
  •     if strings.Compare("out", rest) == 0 {
    
  •         //Opposite Score
    
  •         score_balls_A = append(score_balls_A, t)
    
  •         fmt.Println(t)
    
  •         serveMetux.Unlock()
    
  •         continue
    
  •     }
    
  •     // 4. Prepare to catch the ball from the opposite team
    
  •     catch_chanel_A <- t
    
  • }
    
  • }

  • //Hit

  • func shot(rate int) string {

  • if rand.Intn(100) < rate {
    
  •     return "in"
    
  • } else {
    
  •     return "out"
    
  • }
    
  • }

  • func main() {

  • fmt.Println("Competition begins...")
    
  • //id of initialization ball
    
  • for i := 0; i < serveTotals; i++ {
    
  •     balls_ids <- i + 1
    
  • }
    
  • //Initialize the serving order
    
  • wg.Add(nums + 1) // Accumulated Count
    
  • go serve()
    
  • //time.Sleep(time.Second)
    
  • go playerA("A1", 45)
    
  • go playerA("A2", 60)
    
  • go playerB("B1", 50)
    
  • go playerB("B2", 90)
    
  • wg.Wait()
    
  • fmt.Println("End of Competition.")
    
  • fmt.Printf("A : B = (%d, %d)\n", len(score_balls_A), len(score_balls_B))
    
  • for _, t := range score_balls_A {
    
  •     fmt.Println(t)
    
  • }
    
  • fmt.Println()
    
  • for _, t := range score_balls_B {
    
  •     fmt.Println(t)
    
  • }
    
  • }

Additionally, the implementation of pipeline channel We know that pipeline is a way of communication in the operating system. It is characterized by half-duplex communication and one-way data transmission at a time. Both swoole and golang implement channel, but they are not based on the operating system's pipeline. They only use the same principles

Essentially a queue running in memory, data structure Channel, the underlying implementation is based on shared memory + Mutex mutex mutex exclusion, which implements a user-state high-performance memory queue. This article has detailed swoole source analysis https://zhuanlan.zhihu.com/p/45020194 Channels are divided into buffered and buffered channel s, where no data or full buffers can cause blocking.

Tags: Programming REST Go

Posted on Fri, 05 Jun 2020 10:07:33 -0700 by dvidunis