Error handling and resource release

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

Error handling and resource release

2017-03-20

In the case of error, how to deal with the release of resources, in the go language is quite a test of user experience. If you can put the wrong handling in place, basically can be counted to play very much. Resources mainly refer to Goroutine, but this topic is not specified. I remember saying that for concurrent programming, I have always been in awe, even with the language of go so powerful.

Here are three questions to ask, and no standard answer is given. can be explored together.

    1. Do you want to close the error?
    2. What happens when close is wrong again?
    3. Whether to return error when cancel

OK, now let's put these questions aside and look at a piece of code.

func worker(done chan error) {    err := doSomething()    if err != nil {        done <- err    }    done <- nil}func f() error {    doneCh := make(chan error)    for i:=0; i<workerNum; i++ {        go worker(doneCh)    }    for i:=0; i<workerNum; i++ {        err := <-doneCh        if err != nil {            return err        }    }    return nil}

What's wrong with the error handling of this piece of code? Don't look at the answer first, think for a few minutes ...

...

......

Assuming <-doneCh that the error is returned, then the function f is returned directly, then no one reads the data inside the Donech, so the worker's goroutine will be blocked forever in the done <- err ----leak!

This is a very typical example, the worker's goroutine cannot be freed, then the memory it references cannot be reclaimed, and the program will leak memory. Look back at the title of this article: error handling and resource release. When error handling is not in place, it is easy to miss out on the release of resources.

This place is the result of a direct exit from the error. There are some simple ways to modify it, such as:

Scheme one, with buffer channel, directly to the channel size as the number of workers, there will be no done <- err blocking problems, always put in.

    doneCh := make(chan error, workerNum)

Scenario two, the caller, even if an error is encountered, waits for all workers to complete before returning.

    var err error    for i:=0; i<workerNum; i++ {        err1 := <-doneCh        if err1 != nil && err == nil {            err = err1        }    }    if err {        doSomething()    }

Is it easy to write code that has another problem with error overwriting, preserving the first one, or keeping the last one? Other dozen logs? How do you do it better? You can think about it.

Program three, a separate closech, specifically for the exit.

func worker(done chan error, closed chan struct{}) {    err := doSomething()    select {    case done <- err:    case <-closed:    }}func f() error {    doneCh := make(chan error)    closed := make(chan struct{})    for i:=0; i<workerNum; i++ {        go worker(doneCh, closed)    }    for i:=0; i<workerNum; i++ {        err := <-doneCh        if err != nil {            close(closed)            return err        }    }    return nil}

When you close a channel, all the goroutine that read the channel can be notified, and I've said this technique before.

After reading the code, the mind jumps out and abstracts the problem.

It is possible for us to encounter such a scenario where a sequence of a/b/c operations is done, and each operation takes on a resource. If we have encountered an error when dealing with a, should we recycle the resources of B and C? The answer is yes, the correct error handling, should not occur resource leaks. If the resource provides an operation called Close () and encounters the wrong scenario, we should drop the close (). When is it called?

There are two ways to deal with close in different conventions:

The first is to properly handle the release of resources in the event of an error. That is, after processing a encountered an error, can not directly return, to first close the resources of B and C. Above in programme II and programme San du are examples of this.

The other is to separate error handling from resource release. The process is this, the first allocation of the resources of ABC, the function f() inside the call ABC, regardless f() of whether or not to return the error, is the F return after the release of resources outside. You can change the plan three as an example:

    // 统一分配好资源    closed := make(chan struct{})    doneCh := make(chan error)    for i:=0; i<workerNum; i++ {        go worker(doneCh, closed)    }    // 在f里面处理事件ABC    err := f()    // 再统一释放资源    close(closed)

What about the error when close? The problem is disgusting. Error occurred, want to handle the release of resources and return, but the release of resources may continue to error, very need to notice the error coverage.

The code for Scenario I and program two is actually a little bit imperfect. Why is it? If an error is encountered, the caller is not paying attention to the rest of the results. In contrast, scenario three, if you encounter the first error, it will be close, directly cancel the subsequent operation. and plan one and program two, but also the operation done, wasting resources. Scenario three, in a sense, is actually supporting the cancel operation.

There is a context package in the standard library of go that can provide cancel. This is a very good feature. There is a problem, however, that the cancel operation is completely different from the normal error-handling call chain. Common error-handling call chains are first-level, like a linked list, while Cancel is like a tree. This is a very painful question to think about.

Related Article

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.