[Golang] How to let data collection support concurrent access?

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed. In the go language, the use of channel communication is advocated to replace the explicit synchronization mechanism. But I have found that sometimes it does not seem very good to use the channel communication method (the problem of efficiency is not considered). Suppose you have a collection of accounts that you need to implement on this set, such as finding changes and so on. The operation of this collection must be concurrency-enabled.

If the lock is used (scenario 1)

The implementation is probably like this:
import "sync"type Info struct {age int}type AccountMap struct {accounts map[string]*Infomutex    sync.Mutex}func NewAccountMap() *AccountMap {return &AccountMap{accounts: make(map[string]*Info),}}func (p *AccountMap) add(name string, age int) {p.mutex.Lock()defer p.mutex.Unlock()p.accounts[name] = &Info{age}}func (p *AccountMap) del(name string) {p.mutex.Lock()defer p.mutex.Unlock()delete(p.accounts, name)}func (p *AccountMap) find(name string) *Info {p.mutex.Lock()defer p.mutex.Unlock()res, ok := p.accounts[name]if !ok {return nil}inf := *resreturn &inf}

Using channels to achieve the test (scenario 2)

type Info struct {age int}type AccountMap struct {accounts map[string]*Infoch       chan func()}func NewAccountMap() *AccountMap {p := &AccountMap{accounts: make(map[string]*Info),ch:       make(chan func()),}go func() {for {(<-p.ch)()}}()return p}func (p *AccountMap) add(name string, age int) {p.ch <- func() {p.accounts[name] = &Info{age}}}func (p *AccountMap) del(name string) {p.ch <- func() {delete(p.accounts, name)}}func (p *AccountMap) find(name string) *Info {// 每次查询都要创建一个信道c := make(chan *Info)p.ch <- func() {res, ok := p.accounts[name]if !ok {c <- nil} else {inf := *resc <- &inf}}return <-c}

Here's a question, every time you call find, you create a channel.

Then try to use the channel as a parameter (scenario 3)

Only the implementation of the find function needs to be modified:
// 信道对象作为参数,暴露了实现机制func (p *AccountMap) find(name string, c chan *Info) *Info {p.ch <- func() {res, ok := p.accounts[name]if !ok {c <- nil} else {inf := *resc <- &inf}}return <-c}

To summarize, the problem now is that there are three kinds of solutions that are not satisfactory:

Scenario 1: Using the lock mechanism is not very consistent with the way go solves the problem.

Scenario 2: For queries that need to return results, each query creates a channel to compare waste resources.

Scenario 3: You need to specify the channel object in the function parameters, exposing the implementation mechanism.

So is there any better plan?

2012.12.14: Scenario 2 also has an improved version: Use of pre-allocation and recyclable channel to improve resource utilization. This technique is useful when multiple goroutine wait for an active object to return its own data. For example, the online game server in the login server each player's connection with a goroutine to deal with, another active object on behalf of the account server connection to verify the legitimacy of the account. Player Goroutine will send their respective player account password to the active object and block waiting for the active object to return the validation results. Because multiple players initiate an account verification request at the same time, the active object needs to distribute the returned results, so it can request a channel and wait for the channel when sending the request.

The code is as follows:
type Info struct {age int}type AccountMap struct {accounts map[string]*Infoch       chan func()tokens   chan chan *Info}func NewAccountMap() *AccountMap {p := &AccountMap{accounts: make(map[string]*Info),ch:       make(chan func()),tokens:   make(chan chan *Info, 128),}for i := 0; i < cap(p.tokens); i++ {p.tokens <- make(chan *Info)}go func() {for {(<-p.ch)()}}()return p}func (p *AccountMap) add(name string, age int) {p.ch <- func() {p.accounts[name] = &Info{age}}}func (p *AccountMap) del(name string) {p.ch <- func() {delete(p.accounts, name)}}func (p *AccountMap) find(name string) *Info {// 每次查询都要获取一个信道c := <-p.tokensp.ch <- func() {res, ok := p.accounts[name]if !ok {c <- nil} else {inf := *resc <- &inf}}inf := <-c// 回收信道p.tokens <- creturn inf}

Add a comment on Golang-china:

Xushiwei

In your way, use the channel to actually serialize all requests. In addition, the channel is far greater than the lock in terms of cost. Because the channel itself is obviously implemented with a lock + signal wakeup mechanism.

Steve Wang

Is it possible to summarize this: 1. For concurrent access to data objects that are shared with each goroutine, use a lock to control 2. For communication between Goroutine, use the channel

Longshanksmo

In terms of performance alone, this conclusion is a little hasty now. Concurrency and performance problems are complex, and different scenarios can produce the exact opposite conclusion. There are a number of factors to consider: first, different use conditions, lock granularity is different. In your case, the map operation, the lock granularity is very small. However, if there is some kind of overloaded operation, or there is a blockage, the lock granularity is large. It was not worth the lock at that time. Second, Chan's lock granularity is very small, basic fixed, predictable. In real business, performance predictability is important, determining the resource input and provisioning at deployment time. Most importantly, if all goroutine within a process are running within a single thread, then Chan's lock is not required. So as to really play the coroutine advantage. Now the go compiler doesn't seem to have optimized this yet, and I don't know if it will evolve in the future. In short, the concurrency has not yet been changed

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.