内容简介:在上一篇《什么是data race,考虑如下代码:当alice和bob同时执行如上的操作,最后的存款有几种可能性?
-
版本
golang -- 1.12.4
mongodb -- 4.0
go driver -- 1.0.0
-
简介
在上一篇《 用golang实现 mongodb 数据库连接池-基本篇 》我们实现了mongodb的golang driver按序使用的基本版,但还需要进一步提升效率和高并发安全。本篇张实现高效率协程安全版。
- data race
什么是data race,考虑如下代码:
var balance int
func Deposit(amount int){ balance = balance + amount}
func Balance() int { return balance}
//Alice:
go func(){
bank.Deposit(200) // A1
fmt.Println("=", bank.Balance()) // A2
}()
//Bob
go bank.Deposit(100) // B
当alice和bob同时执行如上的操作,最后的存款有几种可能性?
根据直觉会有3种可能:
| alice first | bob first | alice/bob/alice |
|---|---|---|
| 0 | 0 | 0 |
| A1 200 | B 100 | A1 200 |
| A2 "=200" | A1 300 | B 300 |
| B 300 | A2 "=300" | A2 "=300" |
这个结果最后存款都是剩余300似乎也没什么问题,但是这里还有第4种可能,那就是bob的存款操作发生在A1的balance + amount之后,但是在A1的balance =之前,那么会出现什么?
Data | race
:-: | :-: | :-
| 0 |
A1r | 0 | ...=balance + amount
B | 100 |
A1w | 200 | balace = ...
A2 | "=200" |
现在Alice账户剩余200,在data race中100被程序冲掉。
-
设计
我们使用mutual exclusion的方式进行协程安全设计,具体请参见《 golang实现协程安全的几种方式 》
-
核心代码
const(
MAX_CONNECTION = 10
INITIAL_CONNECTION = 4
AVAILABLE = false
USED = true
)
/*
代码取了一个巧,用实际存放数据库指针的大小ClientPool.size和mongodata.flag来表示上述a,b两个状态
如果mongodata.flag都为USED,那么需要新申请个数据库连接: size++
clientList: the client pool
clientAvailable: the available flag, means the location and available flag in the client pool
size: the size of allocated client pool <= MAX_CONNECTION
*/
type mongodata struct{
client *mongo.Client
pos int
flag bool
}
type ClientPool struct{
clientList [MAX_CONNECTION]mongodata
size int
}
//create a new database connection to the pool
func (cp *ClientPool) allocateCToPool(pos int) (err error){
cp.clientList[pos].client, err = Dbconnect()
if err != nil {
utils.Logger.SetPrefix("WARNING ")
utils.Logger.Println("allocateCToPool - allocateCToPool failed,position: ", pos, err)
return err
}
cp.clientList[pos].flag = USED
cp.clientList[pos].pos = pos
return nil
}
//apply a connection from the pool
func (cp *ClientPool) getCToPool(pos int){
cp.clientList[pos].flag = USED
}
//free a connection back to the pool
func (cp *ClientPool) putCBackPool(pos int){
cp.clientList[pos].flag = AVAILABLE
}
//program apply a database connection
func GetClient() (mongoclient *mongodata, err error) {
mu.RLock()
for i:=1; i<cp.size; i++ {
if cp.clientList[i].flag == AVAILABLE{
return &cp.clientList[i], nil
}
}
mu.RUnlock()
mu.Lock()
defer mu.Unlock()
if cp.size < MAX_CONNECTION{
err = cp.allocateCToPool(cp.size)
if err != nil {
utils.Logger.SetPrefix("WARNING ")
utils.Logger.Println("GetClient - DB pooling allocate failed", err)
return nil, err
}
pos := cp.size
cp.size++
return &cp.clientList[pos], nil
} else {
utils.Logger.SetPrefix("WARNING ")
utils.Logger.Println("GetClient - DB pooling is fulled")
return nil, errors.New("DB pooling is fulled")
}
}
//program release a connection
func ReleaseClient(mongoclient *mongodata){
mu.Lock()
cp.putCBackPool(mongoclient.pos)
mu.Unlock()
}
这样我们就完成了一个高效率协程安全的设计,完整代码地址: https://github.com/kmnemon/golang-mongodb-pool
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- php实现mysql连接池效果实现代码
- java并发实战:连接池实现
- Django+Vue实现WebSocket连接
- 实现WebRTC P2P连接
- Swoole MySQL 连接池的实现
- Swoole Redis 连接池的实现
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JSP 2.0技术手册
杜远君、林康司、林上杰 / 湖北教育出版社,电子工业出版社 / 2004-5-1 / 59.0
本书图文并茂,以丰富的实例为引导,全面介绍了主流的Java Web开发技术——JSP 2.0,重点介绍Java在展示层的两项重要技术:Java Servlet与JavaServer Pages。它们是最重要的Java核心技术。对这两项技术的深入了解,将有助于您未来对于JavaServer Faces(JSF)技术以及Java Web Services技术的学习。 本书分为三大部分,前......一起来看看 《JSP 2.0技术手册》 这本书的介绍吧!