I know an engineer who is well versed in golang programming skills. He/she is experienced, skilled in various engineering problem solving techniques, and has a deep understanding of systems. When it comes to golang’s actual combat problems, he or she can often hit the nail on the head.

When asked what Golang’s Goroutine was, he or she was stunned and said, “It’s kind of like a Java thread pool.” excuse me! I mean, this is bullshit!

So I thought, let me pretend that I know more about goroutine. For those of you who know goroutine, please go around.

So what exactly is a Goroutine pinch?

To understand what a goroutine is, we need to understand what a coroutine is. (Those of you who don’t know coroutine, please raise your legs! — Guo Degang)

A coroutine is a coroutine.

To understand what coroutines are, we need to understand their special form: routines.

A language that is not built to support coroutines, writes functions that we call subroutines, or routines. Subroutine A calling subroutine B means to create A space inside A’s stack for B’s stack. B can continue to call C, C can continue to call D… Note that all subsequent calls share the stack space created by A’s thread. If we write a particularly complex function with nested calls, we are likely to see StackOverFlow! Of course, it’s much easier to run into StackOverFlow if you write A call from A to B, and then B calls an infinite number of function calls from A!

I’m almost done with the routine.

C/C ++/ Java without some special library support, we write functions that call each other as routines.

And routines are special forms of coroutines! (Be thick and black if it’s important)

It is easy to infer that in a thread, the caller routine must wait until the called routine completes and returns. Such as:

public static void funcionA(){
  int resultFromB = functionB();
  System.out.println("B returned : " + resultFromB);
}
Copy the code

If the caller routine is called inside the called routine, it will also open a new function stack to execute. For example, if functionA is called in functionB (ok, I know the person who wrote this is big SB), then another functionA stack is created and executed.

But what about coroutine?

var q := new queue

coroutine produce
    loop
        while q is not full
            create some new items
            add the items to q
        yield to consume

coroutine consume
    loop
        while q is not empty
            remove some items from q
            use the items
        yield to produce
Copy the code

Coroutine produce and consume can use the yield keyword to push enforcement around. We can use yield in this example to mean, “I’ll stop for a minute.”

Produce dropped something into Q, and then indicated that it needed a break so Consume could do some work.

Consume uses the stuff in Q and says it needs to rest and let Produce do some work.

Produce and consume are not subroutines of each other, and each other’s stack is independent.

If produce does not use the yield keyword and calls consume directly, it becomes a subroutine call. So we say subroutine is a special form of coroutine.

Let’s take a look at goroutine:

func main(a){
ch:=make(chan int)
go routineA(ch)
go routineB(ch)
println("goroutines scheduled!")
<-ch
<-ch
}
func routineA(ch chan int){
 println("A executing!")
 ch<- 1
}
func routineB(ch chan int){
 println("B executing!")
 ch<2 -
}
Copy the code

The go keyword is very useful! What he means: Get out!

RoutineA get lost and execute!

RoutineB get lost and execute!

We see that the main function opens two new goroutines and tells them to get lost and execute themselves at some time. We can assert: “Goroutines Scheduled!” This line will be printed to console first. And “A/B executing! “It will come out later. So the question is, when will A and B get the chance to execute?

Answer: When executing a Goroutine encounters system IO (Timer, channel read/write, file read/write…) The Go Scheduler switches off to see if there is another Goroutine to execute, which gives A and B A chance. In fact, this is the concept of a Golang coroutine. Execute a large number of Goroutine coroutines with a small number of threads at the same time, and whoever is calling system IO sits back and lets someone else use the CPU.

So if we look at your service with pprof, we might find thousands of Goroutines, but only two or three kitten threads are actually running.

Extended question: What if I write a function that doesn’t do any system IO?

func noIO(a){
go routineA()
go routineB()
for {
 println("i will never stop!")}}Copy the code

Go Scheduler handles this specifically. With early versions of Go, you’ll see a lot of “I will never stop!” And found routineA and B had little chance of execution. Now what will go1.9 do? Please try it yourself.

Therefore, to sum up: Golang uses the key word go to trigger coroutine scheduling. Compared to the support for coroutines in languages like Python, Golang’s support is very dumb-friendly. For example, python

yield
await
run_until_complete
Copy the code

Could knock you out in a minute.

Hopefully this article will be of some use to you. When I introduced goroutine to White, I thought it would be like this: Goroutine is kind of like a light weight thread. A real thread can schedule many goroutines, and different goroutines can be mounted on different threads to execute. It’s all automatic and programmer friendly.

As an aside, we can set up the system to have only one thread, and all the goroutines will run on that thread. So we can get rid of one really nasty thing:



















































































That’s right, sync.rwmutex.