On the use of goroutine in go language

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

Goroutine in Go is a feature of the go language that supports concurrency at the language level. When I first approached go, I was delighted with the goroutine of Go, and it was easy enough to get to the point of BT. But in the course of the project, it is more and more found that Goroutine is a very easy thing to be abused by everyone. Goroutine is a double-sided blade. Here are some of the sins used by Goroutine:

1 goroutine Pointer transfer is not secure

Fun Main () {request: = Request. Newrequest ()//The Newrequest () here is passed back to a type request with a pointer to go SAVEREQUESTTOREDIS1 (request) Go SaveReuqestToRedis2 (Request) select{}}

Very logic-compliant code:

The main routine open a routine and pass the request to SAVEREQUESTTOREDIS1, and let it store the requests in Redis node 1.

At the same time, open another routine and pass the request to SAVEREUQESTTOREDIS2, and let it store the requests in Redis node 2.

Then the main routine goes into the loop (does not end the process)

The problem is now, SAVEREQUESTTOREDIS1 and saveReuqestToRedis2 two functions actually not I write, but the team another person wrote, I do not know about the implementation of it, do not want to look at the concrete implementation of the internal. But according to the function name, I would, of course, pass the request pointer in.

Well, actually SAVEREQUESTTOREDIS1 and SAVEREQUESTTOREDIS2 are implemented like this:

Func saveRequestToRedis1 (Request *request) {     ...     Request. Tousers = []int{1,2,3}//Here is an assignment operation that modifies the data structure    that the request points to ... Redis. Save (Request)    return}

What's wrong with that? SaveRequestToRedis1 and SaveReuqestToRedis2 Two goroutine modify the same shared data structure, but because the execution of the routine is unordered, we cannot guarantee the request. Tousers settings and Redis.save () are atomic operations, which can cause a bug that actually stores redis data errors.

Well, you can say that this Saverequesttoredis function is implemented with a problem and is not considered to be called using go routine. Think again, this saverequesttoredis concrete implementation is no problem, it should not consider how the upper layer is how to use it. That's my goroutine. The use of the problem, the main routine in the opening of a routine did not confirm that the routine in any of the code has changed the main routine data. Yes, the main routine really need to think about this situation. But according to this idea, so? The main goroutine need to read each line of code in the sub-routine when enabling go routine to determine if there are any modifications to the shared data?? This is in the actual project development process is how to reduce the development speed of one thing Ah!

The go language uses Goroutine to alleviate the development pressure of concurrency, but does not want to add to the development pressure on the other.

It says so much, is to draw a conclusion:

Gorotine is not safe to pass the pointer!!

If the previous example is not covert enough, here's an example:

Fun (This *request) Saveredis () {redis1: = Redis. NEWREDISADDR ("xxxxxx") Redis2: = Redis. NEWREDISADDR ("xxxxxx") go This.saverequesttoredis (redis1) go This.saverequesttoredis (REDIS2) select{}}

Very few people will consider whether the object pointed to by this pointer will be problematic, and here the this pointer passed to routine should be said to be very covert.

2 Goroutine increases the risk factor for the function

This is in fact from the above point. As stated above, passing pointers to a go function is not safe. How can you guarantee that the function you want to invoke does not use go inside the function implementation? There is no way to determine if you do not look at the body of the function in detail.

For example, we'll change the typical example above

Func Main () {request: = Request. Newrequest () saveRequestToRedis1 (Request) SaveRequestToRedis2 (Request) select{}}

Now that we're not using concurrency, that's not going to happen, is it? Chase into the function inside, dumbfounded:

Func saveReqeustToRedis1 (Request *request) {           ...            Go func () {      ...      Request. Tousers = []{1,2,3}     ....     Redis. Save (Request)}}

I'm going to go, there's a goroutine in it, and I've modified the object that the request pointer points to. There's been a mistake here. Well, this problem cannot be avoided if the function is called without looking at the actual implementation within the function. So, what? So, from the worst-case perspective, every calling function is theoretically unsafe! Imagine that this calling function is written by someone who is not a development group, but uses the third-party open source code on the network ... It's really impossible to imagine how long it will take to find this bug.

3 Goroutine of abuse traps

Take a look at this example:

Func main () {Go saverequesttoredises (Request)}func saverequesttoredieses (Request *request) {for _, Redis: = Range redises {Go Redis.saverequesttoredis (request)}} Func Saverequesttoredis (Request *request) {            .....            go func () {                     request. Tousers = []{1,2,3}                        ...                        Redis. Save (Request)            }}

Magic, Go is everywhere, it's like blinking and popping up. This is the abuse of go, everywhere see go, but it is not very clear, where to use go? Why use go? Is goroutine really going to be an efficient upgrade?

The concurrency of the C language is more complex and cumbersome than the concurrency of the go language, so we think before we use it, consider the benefits and disadvantages of using concurrency. Where's go? Almost no.

Processing methods

Here are a few of my ways to deal with these problems:

1 When starting a goroutine, if a function must pass a pointer, but the function level is deep, in the case of security is not guaranteed, pass the pointer to a clone of the object, instead of passing the pointer directly

Fun Main () {request: = Request. Newrequest () Go saveRequestToRedis1 (Request. Clone ()) Go SaveReuqestToRedis2 (Request. Clone ()) select{}}

The clone function needs to be written separately. You can simply follow this method after the structure is defined. Like what:

Func (this *request) Clone () {newrequest: = Newrequst () newrequest.tousers = "Make" ([]int, Len (this). tousers)) Copy (Newrequest.tousers, this. Tousers)}

In fact, from an efficiency perspective, it does create unnecessary cloning operations, consuming a certain amount of memory and CPU. But in my opinion, first of all, for the sake of security, this attempt is worthwhile. Second, if the project does have a high level of efficiency, then you might want to follow this principle in the development phase to use clone, and then in the project optimization phase, as an optimization tool, remove unnecessary clone operations. This will enable the best possible optimization in the context of ensuring safety.

2 When to use go problem

There are two kinds of thinking logic that can be thought of using goroutine:

1 Business logic requires concurrency

For example, a server, receiving a request, the blocking method is that a request processing is completed before the processing of a second request begins. In fact, in the design we will not do this, we will be in the beginning to think of the use of concurrency to handle this scenario, each request to start a goroutine to serve it, so that the parallel effect. This kind of goroutine directly according to the logic of thinking to use Goroutine

2 Performance optimization requires concurrency

One scenario is this: a message needs to be sent to a group of users, and normal logic uses

For _, User: = Range users {sendMessage (user)}

But when it comes to performance issues, we don't do that if the number of users is large, like 10 million users? We do not need to put 10 million users in a routine run processing, consider the 10 million users into 1000 parts, each open a goroutine, a goroutine distribution 10,000 users, this will improve the efficiency of a lot. This is the demand for goroutine on performance optimization.

In terms of the process of project development. In the project development phase, the first idea of the code implementation will directly affect the subsequent development implementation, so in the project development phase should be implemented immediately. But the second is that many small corners of the project can be optimized using goroutine, but if you take into account every optimization strategy in the development phase, it will be a direct disruption to your development approach, which will allow you to extend your development cycle and easily bury potentially unsafe code. Therefore, the second situation in the development phase should not directly use Goroutine, and in the project optimization phase to optimize the idea of the project reconstruction.

Summarize

Summing up, the article wrote so much, not to make you afraid of the use of goroutine, but to emphasize a point of view:

The use of goroutine should be conservative.

Before you knock down the two letters of go, think carefully whether you should use the Goroutine blade.

Subsequent

After you finish this article, also suggest to see Stevewang this article:

Innocent Goroutine.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.