update comment for gmlock

This commit is contained in:
John 2019-06-05 21:58:27 +08:00
parent d1f0fa1a47
commit 841224372b
8 changed files with 130 additions and 55 deletions

View File

@ -52,7 +52,10 @@ func (r *Response) buildInVars(params...map[string]interface{}) map[string]inter
} else {
vars = make(map[string]interface{})
}
vars["Config"] = gins.Config().GetMap("")
// 当配置文件不存在时就不赋值该模板变量,不然会报错
if c := gins.Config(); c.FilePath() != "" {
vars["Config"] = c.GetMap("")
}
vars["Cookie"] = r.request.Cookie.Map()
vars["Session"] = r.request.Session.Map()
vars["Get"] = r.request.GetQueryMap()

View File

@ -20,10 +20,10 @@ import (
// SESSION对象
type Session struct {
id string // SessionId
id string // SessionId
data *gmap.StrAnyMap // Session数据
server *Server // 所属Server
request *Request // 关联的请求
server *Server // 所属Server
request *Request // 关联的请求
}
// 生成一个唯一的SessionId字符串长度18位。

View File

@ -55,20 +55,20 @@ func New(file...string) *Config {
// Customized dir path from env/cmd.
if envPath := cmdenv.Get("gf.gcfg.path").String(); envPath != "" {
if gfile.Exists(envPath) {
c.SetPath(envPath)
_ = c.SetPath(envPath)
} else {
glog.Errorf("Configuration directory path does not exist: %s", envPath)
}
} else {
// Dir path of working dir.
c.SetPath(gfile.Pwd())
_ = c.SetPath(gfile.Pwd())
// Dir path of binary.
if selfPath := gfile.SelfDir(); selfPath != "" && gfile.Exists(selfPath) {
c.AddPath(selfPath)
_ = c.AddPath(selfPath)
}
// Dir path of main package.
if mainPath := gfile.MainPkgPath(); mainPath != "" && gfile.Exists(mainPath) {
c.AddPath(mainPath)
_ = c.AddPath(mainPath)
}
}
return c

View File

@ -13,42 +13,62 @@ var (
locker = New()
)
// 内存写锁如果锁成功返回true失败则返回false;过期时间单位为秒默认为0表示不过期
// TryLock tries locking the <key> with write lock,
// it returns true if success, or if there's a write/read lock the <key>,
// it returns false. The parameter <expire> specifies the max duration it locks.
func TryLock(key string, expire...time.Duration) bool {
return locker.TryLock(key, expire...)
}
// 内存写锁锁成功返回true失败时阻塞当失败时表示有其他写锁存在;过期时间单位为秒默认为0表示不过期
// Lock locks the <key> with write lock.
// If there's a write/read lock the <key>,
// it will blocks until the lock is released.
// The parameter <expire> specifies the max duration it locks.
func Lock(key string, expire...time.Duration) {
locker.Lock(key, expire...)
}
// 解除基于内存锁的写锁
// Unlock unlocks the write lock of the <key>.
func Unlock(key string) {
locker.Unlock(key)
}
// 内存读锁如果锁成功返回true失败则返回false; 过期时间单位为秒默认为0表示不过期
// TryRLock tries locking the <key> with read lock.
// It returns true if success, or if there's a write lock on <key>, it returns false.
func TryRLock(key string) bool {
return locker.TryRLock(key)
}
// 内存写锁锁成功返回true失败时阻塞当失败时表示有写锁存在; 过期时间单位为秒默认为0表示不过期
// RLock locks the <key> with read lock.
// If there's a write lock on <key>,
// it will blocks until the write lock is released.
func RLock(key string) {
locker.RLock(key)
}
// 解除基于内存锁的读锁
// RUnlock unlocks the read lock of the <key>.
func RUnlock(key string) {
locker.RUnlock(key)
}
// 通过闭包的方式写锁执行回调方法<f>,执行完毕后释放写锁
// LockFunc locks the <key> with write lock and callback function <f>.
// If there's a write/read lock the <key>,
// it will blocks until the lock is released.
//
// It releases the lock after <f> is executed.
//
// The parameter <expire> specifies the max duration it locks.
func LockFunc(key string, f func(), expire...time.Duration) {
locker.LockFunc(key, f, expire...)
}
// 通过闭包的方式读锁执行回调方法<f>,执行完毕后释放读锁
// RLockFunc locks the <key> with read lock and callback function <f>.
// If there's a write lock the <key>,
// it will blocks until the lock is released.
//
// It releases the lock after <f> is executed.
//
// The parameter <expire> specifies the max duration it locks.
func RLockFunc(key string, f func()) {
locker.RLockFunc(key, f)
}

View File

@ -12,67 +12,89 @@ import (
"time"
)
// 内存锁管理对象
// Memory locker.
type Locker struct {
m *gmap.StrAnyMap
}
// 创建一把内存锁, 底层使用的是Mutex
// New creates and returns a new memory locker.
// A memory locker can lock/unlock with dynamic string key.
func New() *Locker {
return &Locker{
m : gmap.NewStrAnyMap(),
}
}
// 内存写锁如果锁成功返回true失败则返回false; 过期时间默认为0表示不过期
// TryLock tries locking the <key> with write lock,
// it returns true if success, or if there's a write/read lock the <key>,
// it returns false. The parameter <expire> specifies the max duration it locks.
func (l *Locker) TryLock(key string, expire...time.Duration) bool {
return l.doLock(key, l.getExpire(expire...), true)
}
// 内存写锁锁成功返回true失败时阻塞当失败时表示有其他写锁存在;过期时间默认为0表示不过期
// Lock locks the <key> with write lock.
// If there's a write/read lock the <key>,
// it will blocks until the lock is released.
// The parameter <expire> specifies the max duration it locks.
func (l *Locker) Lock(key string, expire...time.Duration) {
l.doLock(key, l.getExpire(expire...), false)
}
// 解除基于内存锁的写锁
// Unlock unlocks the write lock of the <key>.
func (l *Locker) Unlock(key string) {
if v := l.m.Get(key); v != nil {
v.(*Mutex).Unlock()
}
}
// 内存读锁如果锁成功返回true失败则返回false; 过期时间单位为秒默认为0表示不过期
// TryRLock tries locking the <key> with read lock.
// It returns true if success, or if there's a write lock on <key>, it returns false.
func (l *Locker) TryRLock(key string) bool {
return l.doRLock(key, true)
}
// 内存写锁锁成功返回true失败时阻塞当失败时表示有写锁存在; 过期时间单位为秒默认为0表示不过期
// RLock locks the <key> with read lock.
// If there's a write lock on <key>,
// it will blocks until the write lock is released.
func (l *Locker) RLock(key string) {
l.doRLock(key, false)
}
// 解除基于内存锁的读锁
// RUnlock unlocks the read lock of the <key>.
func (l *Locker) RUnlock(key string) {
if v := l.m.Get(key); v != nil {
v.(*Mutex).RUnlock()
}
}
// 通过闭包的方式写锁执行回调方法<f>,执行完毕后释放写锁
// LockFunc locks the <key> with write lock and callback function <f>.
// If there's a write/read lock the <key>,
// it will blocks until the lock is released.
//
// It releases the lock after <f> is executed.
//
// The parameter <expire> specifies the max duration it locks.
func (l *Locker) LockFunc(key string, f func(), expire...time.Duration) {
l.Lock(key, expire...)
defer l.Unlock(key)
f()
}
// 通过闭包的方式读锁执行回调方法<f>,执行完毕后释放读锁
// RLockFunc locks the <key> with read lock and callback function <f>.
// If there's a write lock the <key>,
// it will blocks until the lock is released.
//
// It releases the lock after <f> is executed.
//
// The parameter <expire> specifies the max duration it locks.
func (l *Locker) RLockFunc(key string, f func()) {
l.RLock(key)
defer l.RUnlock(key)
f()
}
// 获得过期时间没有设置时默认为0不过期
// getExpire returns the duration object passed.
// If <expire> is not passed, it returns a default duration object.
func (l *Locker) getExpire(expire...time.Duration) time.Duration {
e := time.Duration(0)
if len(expire) > 0 {
@ -81,7 +103,14 @@ func (l *Locker) getExpire(expire...time.Duration) time.Duration {
return e
}
// 内存写锁当try==true时如果锁成功返回true失败则返回falsetry==false时成功时立即返回否则阻塞等待
// doLock locks writing on <key>.
// It returns true if success, or else returns false.
//
// The parameter <try> is true,
// it returns false immediately if it fails getting the write lock.
// If <true> is false, it blocks until it gets the write lock.
//
// The parameter <expire> specifies the max duration it locks.
func (l *Locker) doLock(key string, expire time.Duration, try bool) bool {
mu := l.getOrNewMutex(key)
ok := true
@ -102,7 +131,12 @@ func (l *Locker) doLock(key string, expire time.Duration, try bool) bool {
return ok
}
// 内存读锁当try==true时如果锁成功返回true失败则返回falsetry==false时成功时立即返回否则阻塞等待
// doRLock locks reading on <key>.
// It returns true if success, or else returns false.
//
// The parameter <try> is true,
// it returns false immediately if it fails getting the read lock.
// If <true> is false, it blocks until it gets the read lock.
func (l *Locker) doRLock(key string, try bool) bool {
mu := l.getOrNewMutex(key)
ok := true
@ -114,8 +148,9 @@ func (l *Locker) doRLock(key string, try bool) bool {
return ok
}
// 根据指定key查询或者创建新的Mutex
func (l *Locker) getOrNewMutex(key string) (*Mutex) {
// getOrNewMutex returns the mutex of given <key> if it exists,
// or else creates and returns a new one.
func (l *Locker) getOrNewMutex(key string) *Mutex {
return l.m.GetOrSetFuncLock(key, func() interface{} {
return NewMutex()
}).(*Mutex)

View File

@ -11,15 +11,15 @@ import (
"sync"
)
// 互斥锁对象
// The mutex.
type Mutex struct {
mu sync.RWMutex
wid *gtype.Int64 // 当前Lock产生的唯一id(主要用于计时Unlock的校验)
rcount *gtype.Int // RLock次数
wcount *gtype.Int // Lock次数
wid *gtype.Int64 // Unique id for this mutex.
rcount *gtype.Int // RLock count.
wcount *gtype.Int // Lock count.
}
// 创建一把内存锁使用的底层RWMutex
// NewMutex creates and returns a new mutex.
func NewMutex() *Mutex {
return &Mutex{
wid : gtype.NewInt64(),
@ -28,46 +28,55 @@ func NewMutex() *Mutex {
}
}
// Lock locks mutex for writing.
// If the lock is already locked for reading or writing,
// Lock blocks until the lock is available.
func (l *Mutex) Lock() {
l.wcount.Add(1)
l.mu.Lock()
l.wid.Add(1)
}
// 安全的Unlock
// Unlock unlocks the write lock.
// It is safe to be called multiple times.
func (l *Mutex) Unlock() {
if l.wcount.Val() > 0 {
if l.wcount.Add(-1) >= 0 {
l.mu.Unlock()
} else {
// 标准库这里会panic
l.wcount.Add(1)
}
}
}
// RLock locks mutex for reading.
func (l *Mutex) RLock() {
l.rcount.Add(1)
l.mu.RLock()
}
// 安全的RUnlock
// RUnlock undoes a single RLock call;
// it does not affect other simultaneous readers.
// It is a run-time error if rw is not locked for reading
// on entry to RUnlock.
// It is safe to be called multiple times.
func (l *Mutex) RUnlock() {
if l.rcount.Val() > 0 {
if l.rcount.Add(-1) >= 0 {
l.mu.RUnlock()
} else {
// 标准库这里会panic
l.rcount.Add(1)
}
}
}
// 不阻塞Lock
// TryLock tries locking the mutex with write lock,
// it returns true if success, or if there's a write/read lock the mutex,
// it returns false.
func (l *Mutex) TryLock() bool {
// 初步读写次数检查, 但无法保证原子性
// The first check, but it cannot ensure the atomicity.
if l.wcount.Val() == 0 && l.rcount.Val() == 0 {
// 第二次检查, 保证原子操作
// The second check, it can ensure the atomicity.
if l.wcount.Add(1) == 1 {
l.mu.Lock()
l.wid.Add(1)
@ -79,9 +88,10 @@ func (l *Mutex) TryLock() bool {
return false
}
// 不阻塞RLock
// TryRLock tries locking the mutex with read lock.
// It returns true if success, or if there's a write lock on mutex, it returns false.
func (l *Mutex) TryRLock() bool {
// 只要不存在写锁
// There must be no write lock on mutex.
if l.wcount.Val() == 0 {
l.rcount.Add(1)
l.mu.RLock()

View File

@ -21,6 +21,11 @@ import (
"text/template"
)
const (
// Template name for content parsing.
gCONTENT_TEMPLATE_NAME = "template content"
)
var (
// Templates cache map for template folder.
templates = gmap.NewStrAnyMap()
@ -103,7 +108,8 @@ func (view *View) Parse(file string, params...Params) (parsed string, err error)
if err != nil {
return "", err
}
gmlock.LockFunc("gview-template-parsing:" + folder, func() {
// Using memory lock to ensure concurrent safety for template parsing.
gmlock.LockFunc("gview-parsing:" + folder, func() {
tpl, err = tpl.Parse(gfcache.GetContents(path))
})
if err != nil {
@ -149,8 +155,14 @@ func (view *View) Parse(file string, params...Params) (parsed string, err error)
func (view *View) ParseContent(content string, params...Params) (string, error) {
view.mu.RLock()
defer view.mu.RUnlock()
tpl := template.New("template content").Delims(view.delimiters[0], view.delimiters[1]).Funcs(view.funcMap)
tpl, err := tpl.Parse(content)
err := (error)(nil)
tpl := templates.GetOrSetFuncLock(gCONTENT_TEMPLATE_NAME, func() interface {} {
return template.New(gCONTENT_TEMPLATE_NAME).Delims(view.delimiters[0], view.delimiters[1]).Funcs(view.funcMap)
}).(*template.Template)
// Using memory lock to ensure concurrent safety for content parsing.
gmlock.LockFunc("gview-parsing:content", func() {
tpl, err = tpl.Parse(content)
})
if err != nil {
return "", err
}

View File

@ -3,20 +3,15 @@ package main
import (
"github.com/gogf/gf/g"
"github.com/gogf/gf/g/net/ghttp"
"github.com/gogf/gf/g/os/gcache"
)
func main() {
s := g.Server()
s.BindHandler("/", func(r *ghttp.Request) {
rs :="GF(Go Frame)是一款模块化、松耦合、生产级的Go应用开发框架。提供了常用的核心开发组件缓存、日志、文件、时间、队列、数组、集合、字符串、定时器、命令行、文件锁、内存锁、对象池、连接池、数据校验、数据编码、文件监控、定时任务、数据库ORM、TCP/UDP组件、进程管理/通信、 并发安全容器等等。并提供了Web服务开发的系列核心组件Router、Cookie、Session、路由注册、配置管理、模板引擎等等支持热重启、热更新、多域名、多端口、多服务、HTTPS、Rewrite等特性。"
Weijin_word := gcache.Get("weijin_word")
if Weijin_word == nil {
Weijin_word = gcache.GetOrSet("weijin_word", rs, 0)
}
//此行压测会提示map并发错误 webbench -c 8000 -t 60 http://IP 局域网两台机器测试
r.Response.WriteTpl("layout.html", g.Map{
"Contentb": Weijin_word,
r.Response.WriteTplContent(rs, g.Map{
"Contentb": 1,
})
})
s.SetPort(8199)