The first thing you need to know is how the operating system plays threads. A thread is a stack plus a heap of resources. Operating system One will let the CPU run thread A, one will let the CPU run thread B, rely on A and B stack to save the execution state of A and B. Each thread has his own stack.
But the thread is old and expensive and can't afford that money, so go invented the goroutine. It basically means that each goroutine is assigned a stack inside the heap to simulate the line stacks. Let's say you have 3 goroutine,a,b,c, and you get three stacks out of the heap. Then go lets a single-threaded scheduler start running them three. Equivalent to {A (); B (); C ()}, continuous, serial run.
Unlike the operating system, the operating system can shut down your thread and switch to another thread, anywhere. This single-threaded scheduler not that ability Ah, he is the user space of a simple code, he ran a when the control is in the code of a. A no one can do it without quitting.
So a run a short period after the initiative to say, Boss (scheduler), I do not want to run, help me to keep all my state on my own stack, let me take a break. At this point you can be seen as a return. A returned B can run, then B runs a short paragraph saying, run enough, save the state, return, and then C run again. C ran a section also returned.
This runs through {A (); B (); C ()}, we found that it was as if they had only run a short period of time. So the outside is going to wrap a loop, roughly:
Goroutine_list = [A, B, C]while (goroutine): for goroutine in goroutine_list:r = Goroutine () if r.finished (): Goroutine_list.remove (R)
For example, after running a lap a,b,c who did not finish, then go back to a to execute once. Since we keep a stack in the heap, this time we can copy and paste a stack into the system stack (I am very sure that the real situation is not so fun, it is OK), and then call a, this time because a is running to half of their own said jumped out, so will be from just jumped out of the place to continue to execute. For example, the inside of a is roughly the same.
def A: where you last ran = where did you find the last time? Read all temporary variables goto last run where a = 1 print ("Do something") Go.scheduler. Save the program pointer//settings "Where's this run?" Go.sc Heduler. Save temporary variables Go.scheduler. Run enough _ substitution//equivalent to return print ("Do Something Again") print (a)
First run a, because this is the first time, will print do something, then save the TEMP variable A, and save the place to go and then return. One more run. A, he will find the next sentence of the last place to return, then restore the temporary variable A, then run, will print "Do Something Again" and 1
So you see, the key is that every goroutine runs and makes a run. Generally support this kind of thing (called coroutine) language is to let each coroutine himself say, I ran enough, substitution. The place where Goroutine is more literary is that he can help you judge when "run out".
One of the more than half is the "asynchronous concurrency" you're talking about. Go to each asynchronous concurrency operation, like you said the file access, network access, and so on all wrapped up, wrapped into a seemingly simple and synchronous "method", such as String readFile (I am blind to cite examples). But the magic is that this method actually invokes "asynchronous concurrency" operations, such as the asyncreadfile provided by an operating system. As you know, this asynchronous method returns quickly.
So you wrote it yourself in some goroutine.
string s = Go.file.readFile ("/root")
In fact, go secretly executed an operating system API Asyncreadfile. After running, this method will say, my current goroutine run enough to save the results of the asynchronous operation just run down, substitution:
Actually handler H = someos.asyncreadfile ("/root")///Soon returns a Handlerwhile (!h.finishedasyncreadfile ())://quickly returns to y/n Go.scheduler. Save status () Go.scheduler. Run enough _ substitution ()//= return, but next time you'll start with the next sentence. String s = H.getresultfromasyncread ()
Then scheduler took a goroutine and ran away. The next time to run back to that Goroutine, he looked, said that the asyncreadfile in the end did not ah, if not, then change a person. If it's done, then take out the results and do what. So you seem to have written a synchronous operation that has been replaced by go for an asynchronous operation.
There is another case where a goroutine executes a blocking system call that cannot be called asynchronously, and Goroutine cannot play the trick of the asynchronous invocation. He'll move you to a real line thread let you wait in that county, he bite to run other goroutine. Like a definition.
def a:print ("Do Something") Go.os.InvokeSomeReallyHeavyAndBlockingSystemCall () print ("Do something 2")
Go will help you turn
def true A:print ("Do something") thread t = new Thread (() = {Somereallyheavyandblockingsystemcall (); }) T.start () while!t.finished (): Go.scheduler. Save status Go.scheduler. Run enough _ substitution print ("finished")
So true A is still not blocking, or can play happily with other small partners (Goroutine), but he has actually accounted for a real system thread.
Of course there is a situation where a does not invoke any possible "asynchronous concurrency" operation, nor does it invoke any synchronous system calls, but rather kept the CPU (for example, using a dead loop to invoke a++). In the early go, this a will block the entire program. There seems to be some way to deal with the new version of Go, such as if you call any other function in a, there is a chance that you will be kicked off the substitution. It seems that I can take the initiative to say that I want to substitute, you can check the new go spec