Home > Backend Development > Golang > Let's talk about concurrent programming in Go (1)

Let's talk about concurrent programming in Go (1)

咔咔
Release: 2021-07-07 16:36:55
Original
2228 people have browsed it

Let’s talk about Go’s goroutine and Channel

  • Preface
  • 1. Goroutine
    • Definition
    • First look at the case to know how to use goroutine
    • What is it
  • 2. Channel
    • Basic usage
    • Pass channel as a parameter
    • Create multiple channels
    • Use channel as return value
    • buffer channel
    • channel close

    Recommended related articles: " Talk about concurrent programming in Go (2) "

    ##Foreword

When I was learning the Go language before, I skipped it when I saw groutine and channel.

I didn’t take it seriously at all at the time, why do you think it’s so complicated? (My state of mind at the time)

Recently I was looking at the concurrent programming of go, and found that it all used this content, so I had no choice but to bite the bullet, but you will find that after watching It doesn't look that difficult.

Sometimes you can put things you don’t want to look at first, and then look at them after you focus your attention. You will get unexpected gains.

Today’s article is a simple explanation. Kaka has also signed up for a go course. In which course can I see if I can get more understanding? I will continue it later. Depth added.

1. goroutine

    Just add go before the function
  • There is no need to distinguish whether it is an asynchronous function in the definition
  • The scheduler switches at the appropriate point. There are many points. , here is just a reference, there is no guarantee of switching, and there is no guarantee that it will not be switched in other places. IO operations, channels, waiting for locks, function calls, runtime.Gosched(), etc. . .
  • Use race to detect data access conflicts

First look at the case to know how to use goroutine

Let’s look at a case first

Lets talk about concurrent programming in Go (1)

##This case is a simple concurrent execution code, in go There is just one keyword in it: go.

So let’s take a look at what this code will output

Lets talk about concurrent programming in Go (1)

From As you can see in the picture above, this line of code outputs nothing and exits directly. So what exactly is going on?

The reason for exiting directly is because the main and fmt printing in our code are executed concurrently. If fmt prints data urgently before it comes, the outer loop has already ended. , and then exited directly.

In the go language! Assume that after a main function exits, it will directly kill all goroutines, so the phenomenon is that the urgent printing data is returned before the goroutine comes.

So are you wondering, how can you see the printed data? In fact, it is very simple, just don't exit in a hurry after the main function is executed, and give it some time to wait. Look at the case

Lets talk about concurrent programming in Go (1)

The desired result this time is displayed.

In this case, the number of goroutines opened is 10, so what will happen if it is changed to 1000?

The result display is still displayed normally, just like 1,000 people printing things at the same time.

So what does setting 10 have to do with 1000?

Anyone who is familiar with the operating system should know that there is no problem in opening 10 threads, and there is no big problem in opening 100 threads, but it is almost enough.

Generally, a system can open dozens of threads, but if 1,000 people are required to do one thing at the same time, threads cannot be used to solve the problem, and an asynchronous method is required.

But in go language! Just use the go keyword directly and it can be executed concurrently.

Next let’s talk about why go can print 1000 at the same time.

What is

Let’s first look at the difference between coroutines and threads.

Coroutines can be understood as lightweight threads, non-preemptive multitasking, and coroutines actively hand over control rights.

Everyone should know that threads can be switched by the operating system at any time, so threads are preemptive multitasking. Threads have no control, even if a statement is executed. Half of it will be cut off by the operating system and then transferred to other threads for operation.

On the contrary, for the coroutine, when to hand over control rights and when not to hand over control rights are actively decided internally by the coroutine. It is precisely because of this non-preemption formula, so it is called lightweight.

And Multiple coroutines can run on one or more threads.

2. channel

In the first section, we learned that a lot of goroutines can be opened in go, so the two-way channel between goroutines is channel

Lets talk about concurrent programming in Go (1)

Basic usage

Lets talk about concurrent programming in Go (1)

##From the picture above In the case, you can see that you can directly use the make function to create a channel.

The seventh and eighth lines are to send data to the channel.

So can this case be run? Let’s try it

Lets talk about concurrent programming in Go (1)

You can see that an error has been reported at this time. The error means that a deadlock will occur when sending 1 to the channel.

Then go back to the previous picture.

Lets talk about concurrent programming in Go (1)

As we have said above, channel is an interaction between goroutine and goroutine.

But in this case there is only one goroutine missing, so another goroutine is needed to receive it.

Now you should know how to start a goroutine.

Lets talk about concurrent programming in Go (1)

In the above picture we newly opened another goroutine, and then used an infinite loop to accept the value sent by the channel and print it come out.

But you will find that we sent two pieces of data to the channel, but the printing result at this time has only one piece of data. But it’s better than what we started with, right!

So why does this happen?

You can understand the execution flow of the code. First, a 1 is sent to the channel, and then the first value is obtained in a loop and printed.

Then send data 2 to the channel, but exit directly before printing, which results in the phenomenon that only data 1 is displayed but not data 2.

You should already know how to solve this problem through Kaka’s description.

That is to add a delayed exit time to the function channelDome.

Lets talk about concurrent programming in Go (1)

Pass channel as a parameter

As you can see above, go is followed by a closure function. The c used in this closure is the outer c used.

So is it possible to pass this c using parameters? The answer is yes.

Lets talk about concurrent programming in Go (1)

Of course, other parameters can also be passed

Lets talk about concurrent programming in Go (1)

#You can see from the above picture that not only the channel but also the id parameter is passed, and the code can also be directly optimized into the enclosed part. , that is, taking the value directly from the channel.

Create multiple channels

Lets talk about concurrent programming in Go (1)

From As can be seen in the above figure, everyone has his own channel, and then distributes it. After distribution, everyone will receive their own received value and print it out.

Similarly, you can see that we have added a new for loop at line 26 to send data to the channel.

Lets talk about concurrent programming in Go (1)

From the running results, you will find that the order of printing is confusing, such as the two values ​​​​receive i and receive I.

Do you have any doubts at this time? When we send data to the channel, we send it in order! Then they must be received in order when receiving.

Since we are very sure that the data is sent in order, the problem can only occur with Printf.

Because Printf has IO and is scheduled by goroutine, then Printf at this time is out of order, but the received values ​​will be printed out one by one.

Use channel as the return value

The cases in the previous sections are all created by channel and then used as parameter passed in.

Then this section will return the channel as a return value.

Lets talk about concurrent programming in Go (1)

Source code

package mainimport (
	"fmt"
	"time")func createWorker(id int) chan int {
	c := make(chan int)
	go func() {
		for {
			fmt.Printf("Worker %d receive %c\n", id, 
Copy after login

From here you can see that we will The function was changed to the createWorker function, because the channel is created directly in this function.

Then the value received by the channel is printed through a coroutine.

Return the channel.

Let’s take a look at the running results

Lets talk about concurrent programming in Go (1)

Through the running results, we can know that our code writing is still correct, but you can see how to use the channel returned at this time very intuitively

But if the code When the number is large, you don't know how to use this channel at all, and all this code needs to be simply modified.

Then what needs to be done is to tell people outside how to use it.

Lets talk about concurrent programming in Go (1)

It can be known from the above code that data is sent to the channel, then in createWorkerThe channel returned by the method should be marked

Lets talk about concurrent programming in Go (1)

So the current code looks like this. We directly mark the direction of the return value channel of the createWorker method. The function is to send data.

Then when printing, it will be the receipt, which looks very intuitive.

After modifying the above two steps, you will find that createWorker calls an error, Cannot use 'createWorker(i)' (type chanWhen you see the error, you should know that the two types are not equal.

Lets talk about concurrent programming in Go (1)

After modification, you will find that the compilation is correct and no error message is reported.

Lets talk about concurrent programming in Go (1)也是ok的。

Lets talk about concurrent programming in Go (1)

本小节源码

package mainimport (
	"fmt"
	"time")func createWorker(id int) chan
Copy after login

buffer channel

学习了这么久了,那么咔咔问你一个问题,这段代码执行会发生什么?

Lets talk about concurrent programming in Go (1)

Yes, an error will occur, because as mentioned at the beginning of the article, to send data to a channel, you need to open another coroutine to receive the data.

Although the coroutine is said to be lightweight, after sending data, it is necessary to switch the coroutine to receive data, which is very resource intensive.

Then this is what I will explain to you in this section.

buffer channel

Create a channel that can have 3 buffers, and then send 3 data to the channel.

You can also know from the results of running at the same time that deadlock is not occurring.

A question for you, what will happen if you send a data 4 to the buffer?

Lets talk about concurrent programming in Go (1)

You are smart, you must have thought of the result, yes, reported itdeadlock

Then we use the previous worker to receive the channel data.

Lets talk about concurrent programming in Go (1)

But you will find that the running result still does not print out the 1,2,3,4 sent in.

This question has been asked several times now. You can try to ask yourself how you should solve this situation.

Lets talk about concurrent programming in Go (1)

Just add a delay time. By the way, I would like to explain to you that the previous case printed Letters, %c used for all formatting, now print numbers, so changed to %d, a small change.

Establishing a channel in this way has a certain effect on improving performance.

Have you discovered a problem so far, that is, when sending a channel, you don’t know when it has been sent.

Let’s look at this issue next.

channel closed

Borrow the code from the previous case to continue the explanation.

Lets talk about concurrent programming in Go (1)
What is inconsistent with the previous code is that we added close at the end. It should be noted that close is closed on the sender.

You will see that the running results are not satisfactory. You will find that although 1,2,3,4 are received.

But a lot of 0s were received below, but only one piece of data was captured in the screenshot.

Although the sender closes the channel, the worker will still receive the data when the channel is closed. This does not mean that the data will not be received after the channel is closed.

But when the sender sets channelle to close, the data received are all 0, that is, the value of the parameter c chan int passed by the worker method is 0. .

Now our channel is of type int, and we receive 0. Then if it is a string type, what is received is an empty string.

How long will this take? That is the one millisecond time we set.

If you were asked to change this program, do you have any ideas? If you have no idea, just sway with the rhythm of this click.

Lets talk about concurrent programming in Go (1)

In the function worker, two values ​​are used to receive, n is the channel c passed over. ok is to determine whether the value exists.

You can see the running results, and you will no longer receive 0 data.

In addition to this way of writing, there is a simpler way.

Lets talk about concurrent programming in Go (1)

Persistence in learning, persistence in writing, and persistence in sharing are the beliefs that Kaka has always adhered to since its beginning. I hope that Kaka’s articles on the huge Internet can bring you a little bit of help. I’m Kaka, see you next time.

The above is the detailed content of Let's talk about concurrent programming in Go (1). For more information, please follow other related articles on the PHP Chinese website!

Related labels:
go
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template