当前位置: 首页 > news >正文

做网站前的准备wordpress php 得到页面描述

做网站前的准备,wordpress php 得到页面描述,如何使用网络营销策略,吉林黄页电话查询golang中内置了map关键字#xff0c;但是它是非线程安全的。从go 1.9开始#xff0c;标准库加入了sync.Map#xff0c;提供用于并发安全的map。普通map的并发问题map的并发读写代码func main() { m : make(map[int]int) go func() { for { _ m[1] // 读 } }(… golang中内置了map关键字但是它是非线程安全的。从go 1.9开始标准库加入了sync.Map提供用于并发安全的map。普通map的并发问题map的并发读写代码func main() { m : make(map[int]int) go func() { for { _ m[1] // 读 } }() go func() { for { m[2] 2 // 写 } }() select {} // 维持主goroutine}以上是一段并发读写map的代码, 其中一个goroutine一直读另外一个goroutine一直写。即使读写的map键不相同且不存在扩容等操作代码还是会报错。fatal error: concurrent map read and map write锁map那普通map有没有能力实现并发安全呢答案是肯定的。通过给map额外绑定一个锁(sync.Mutex或sync.RWMutex)封装成一个新的struct实现并发安全。定义带有锁的对象Mtype M struct { sync.RWMutex Map map[int]int}执行并发读写func main() { m : M{Map: make(map[int]int)} go func() { for { m.RLock() v : m.Map[2] // 读      fmt.Println(v) m.RUnlock() } }() go func() { for i : 1; i 0; i { m.Lock() m.Map[2] i // 写 m.Unlock() } }() select {}}在读goroutine读数据时通过读锁锁定在写goroutine写数据时写锁锁定程序就能并发安全的运行运行结果示意如下。...112311241125...sync.Map既然通过加锁的方式就能解决map的并发问题实现方式简洁并且利用读写锁而不是Mutex可以进一步减少读写的时候因为锁而带来的性能损耗。那么为什么还会有sync.Map的出现当map的数据量非常大时会引发并发的大量goroutine争夺同一把锁这种现象将直接导致性能的急剧下降。在java中有类似于map的hashMap它同样是并发不安全但是JDK提供了线程安全的ConcurrentHashMap它在面对上述场景时其核心解决方案是锁分段技术即内部使用多个锁每个区间共享一把锁当多线程访问map中的不同数据段的数据时线程间就不会存在锁竞争从而提高了并发访问效率。那sync.Map采取的是什么策略来提升并发性能的呢sync.Map的源码结构(基于1.14.1)type Map struct {  // 此锁是为了保护Map中的dirty数据  mu Mutex  // 用来存读的数据只读类型不会造成读写冲突  read atomic.Value // readOnly  // dirty包含最新的写入数据(entry)在写的同时将read中未删除的数据拷贝到dirty中  // 因为是go中内置的普通map类型且涉及写操作所以需要通过mu加锁  dirty map[interface{}]*entry  // 当读数据时,该字段不在read中尝试从dirty中读取不管是否在dirty中读取到数据misses1  // 当累计到len(dirty)时会将dirty拷贝到read中并将dirty清空以此提升读性能。 misses int}(左右滑动查看完整代码图片)在sync.Map中用到了两个冗余数据结构read、dirty。其中read的类型为atomic.Value它会通过atomic.Value的Load方法将其断言为readOnly对象。read, _ : m.read.Load().(readOnly) // m为sync.Map因此read的真实类型即是readOnly其数据类型如下。type readOnly struct {  // read 中的go内置map类型但是它不需要锁。  m       map[interface{}]*entry  // 当sync.Map.diry中的包含了某些不在m中的key时amended的值为true.  amended bool}(左右滑动查看完整代码图片)amended属性的作用是指明dirty中是否有readOnly.m中未包含的数据因此当对sync.Map的读操作在read中找不到数据时将进一步到dirty中查找。readOnly.m和Map.dirty中map存储的值类型是*entry,它包含一个指针p指向用户存储的value值。type entry struct { p unsafe.Pointer // *interface{}}entry.p的值有三种类型nilentry已经被删除且m.dirty为nilexpungedentry被删除m.dirty不为nil但entry不存在m.dirty中其他entry有效记录在m.read中若dirty不为空也会记录在dirty中。虽然read和dirty存在冗余数据但是这些数据entry是通过指针指向的因此尽管Map的value可能会很大但是空间存储还是足够的。以上是sync.Map的数据结构下面着重看看它的四个方法实现Load、Store、Delete和Range。Load加载方法通过提供的键key查找对应的值value。func (m *Map) Load(key interface{}) (value interface{}, ok bool) {  // 首先从m.read中通过Load方法得到readOnly read, _ : m.read.Load().(readOnly)  // 从read中的map中查找key e, ok : read.m[key]  // 如果在read中没有找到且表明有新数据在diry中(read.amended为true)  // 那么就需要在dirty中查找这时需要加锁。 if !ok read.amended { m.mu.Lock()    // 双重检查:避免在本次加锁的时候有其他goroutine正好将Map中的dirty数据复制到了read中。    // 能发生上述可能的原因是以下两行代码语句并不是原子操作。  // if !ok read.amended { // m.mu.Lock() // }    // 而Map.read其并发安全性的保障就在于它的修改是通过原子操作进行的。    // 因此需要再检查一次read. read, _ m.read.Load().(readOnly) e, ok read.m[key]    // 如果m.read中key还是不存在且dirty中有新数据则检查dirty中的数据。 if !ok read.amended { e, ok m.dirty[key]      // 不管是否从dirty中得到了数据都会将misses的计数1 m.missLocked() } m.mu.Unlock() } if !ok { return nil, false }  // 通过Map的load方法将entry.p加载为对应指针再返回指针指向的值 return e.load()}(左右滑动查看完整代码图片)Map.missLocked函数是保证sync.Map性能的重要函数它的目的是将存在有锁的dirty中的数据转移到只读线程安全的read中去。func (m *Map) missLocked() { m.misses // 计数1 if m.misses len(m.dirty) { return }  m.read.Store(readOnly{m: m.dirty}) // 将dirty数据复制到read中去 m.dirty nil // dirty清空 m.misses 0 // misses重置为0}(左右滑动查看完整代码图片)Store该方法更新或新增键值对key-value。func (m *Map) Store(key, value interface{}) {  // 如果m.read中存在该键且该键没有被标记删除(expunged)  // 则尝试直接存储(见entry的tryStore方法)  // 注意 如果m.dirty中也有该键(key对应的entry)由于都是通过指针指向所有m.dirty中也会保持最新entry值。 read, _ : m.read.Load().(readOnly) if e, ok : read.m[key]; ok e.tryStore(value) { return  }  // 如果不满足上述条件即m.read不存在或者已经被标记删除 m.mu.Lock() read, _ m.read.Load().(readOnly)  if e, ok : read.m[key]; ok { // 如果read中有该键    if e.unexpungeLocked() { // 判断entry是否被标记删除      // 如果entry被标记删除则将entry添加进m.dirty中 m.dirty[key] e }    // 更新entry指向value地址 e.storeLocked(value)  } else if e, ok : m.dirty[key]; ok { //dirty中有该键更新 e.storeLocked(value)  } else { // dirty和read中均无该键新增    if !read.amended { // 表明dirty中没有新数据在dirty中增加第一个新键      m.dirtyLocked() // 从m.read中复制未删除的数据到dirty中 m.read.Store(readOnly{m: read.m, amended: true}) }    m.dirty[key]  newEntry(value) // 将entry增加到dirty中 } m.mu.Unlock()}(左右滑动查看完整代码图片)Store的每次操作都是先从read开始当不满足条件时才加锁操作dirty。但是由于存在从read中复制数据的情况(例如dirty刚复制完数据给m.read又来了一个新键)当m.read中数据量很大时可能对性能造成影响。Delete删除某键值。func (m *Map) Delete(key interface{}) { read, _ : m.read.Load().(readOnly) e, ok : read.m[key] if !ok read.amended { m.mu.Lock() read, _ m.read.Load().(readOnly) e, ok read.m[key] if !ok read.amended { delete(m.dirty, key) } m.mu.Unlock() } if ok { e.delete() }}// 如果read中有该键则从read中删除其删除方式是通过原子操作func (e *entry) delete() (hadValue bool) { for { p : atomic.LoadPointer(e.p)    // 如果p指针为空或者被标记清除 if p nil || p expunged { return false } // 通过原子操作将e.p标记为nil. if atomic.CompareAndSwapPointer(e.p, p, nil) { return true } }}(左右滑动查看完整代码图片)Delete中的逻辑和Store逻辑相似都是从read开始如果这个key(也即是entry)不在read中且dirty中有新数据则加锁从dirty中删除。注意和Load与Store方法一样也是需要双检查。Range想要遍历sync.Map不能通过for range的形式因此它自身提供了Range方法通过回调的方式遍历。func (m *Map) Range(f func(key, value interface{}) bool) { read, _ : m.read.Load().(readOnly)  // 判断dirty中是否有新的数据  if read.amended { m.mu.Lock()    // 双检查 read, _ m.read.Load().(readOnly) if read.amended {      // 将dirty中的数据复制到read中 read readOnly{m: m.dirty} m.read.Store(read) m.dirty nil m.misses 0 } m.mu.Unlock() }  // 遍历已经整合过dirty的read for k, e : range read.m { v, ok : e.load() if !ok { continue } if !f(k, v) { break } }}(左右滑动查看完整代码图片)sync.Map的优化总结1. 空间换时间通过两个冗余的数据结构(read、write)减小锁对性能的影响。2. 读操作使用read避免读写冲突。3. 动态调整通过misses值避免dirty数据过多。4. 双检查机制避免在非原子操作时产生数据错误。5. 延迟删除机制删除一个键值只是先打标记只有等提升dirty(复制到read中并清空自身)时才清理删除的数据。6. 优先从read中读、改和删除因为对read的操作不用加锁大大提升性能。sync.Map的使用例子func main() { var sm sync.Map  // 注意同一个sync.Map和map不一样每个item的key或value可以和其他的数据类型不一样  // 只要满足key能hash即可 sm.Store(1, a) sm.Store(b, 2) sm.Store(c, 3)  // 和map获取key值类似  if v, ok : sm.Load(b); ok { fmt.Println(v) } // 删除某个key的键值对 sm.Delete(1)  // 参数fun中的参数是遍历获得的key和value返回一个bool值  // 返回true时继续遍历  // 返回false遍历结束 sm.Range(func(key, value interface{}) bool { fmt.Println(key,value) return true })}(左右滑动查看完整代码图片)输出2b 2c 3sync.Map的性能在Go源码$GOROOT/src/sync中提供了测试代码。map_reference_test.go:  定义了测试用的mapInterface接口sync.Map、RwMutexMap和DeepCopyMap对象实现该接口方法。map_test.go: 三个对象的方法测试代码。map_bench_test.go:  三个对象的benchmark性能对比测试代码。在小菜刀的机器上运行性能测试结果如下。$ go test -benchLoadMostlyHits -benchmemBenchmarkLoadMostlyHits/*sync_test.DeepCopyMap-8 80252629 13.5 ns/op 7 B/op 0 allocs/opBenchmarkLoadMostlyHits/*sync_test.RWMutexMap-8 23025050 51.8 ns/op 7 B/op 0 allocs/opBenchmarkLoadMostlyHits/*sync.Map-8 67718686 14.9 ns/op 7 B/op 0 allocs/op$ go test -benchLoadMostlyMisses -benchmemBenchmarkLoadMostlyMisses/*sync_test.DeepCopyMap-8 128480215 11.2 ns/op 7 B/op 0 allocs/opBenchmarkLoadMostlyMisses/*sync_test.RWMutexMap-8 23989224 47.4 ns/op 7 B/op 0 allocs/opBenchmarkLoadMostlyMisses/*sync.Map-8 132403878 9.30 ns/op 7 B/op 0 allocs/op$ go test -benchLoadOrStoreBalanced -benchmemBenchmarkLoadOrStoreBalanced/*sync_test.RWMutexMap-8 3909409 553 ns/op 99 B/op 2 allocs/opBenchmarkLoadOrStoreBalanced/*sync.Map-8 3574923 368 ns/op 97 B/op 3 allocs/op$ go test -benchLoadOrStoreUnique -benchmemBenchmarkLoadOrStoreUnique/*sync_test.RWMutexMap-8 2053806 647 ns/op 174 B/op 2 allocs/opBenchmarkLoadOrStoreUnique/*sync.Map-8 2456720 577 ns/op 140 B/op 4 allocs/op$ go test -benchLoadOrStoreCollision -benchmemBenchmarkLoadOrStoreCollision/*sync_test.DeepCopyMap-8 153679003 8.18 ns/op 0 B/op 0 allocs/opBenchmarkLoadOrStoreCollision/*sync_test.RWMutexMap-8 13718534 87.9 ns/op 0 B/op 0 allocs/opBenchmarkLoadOrStoreCollision/*sync.Map-8 175620835 7.08 ns/op 0 B/op 0 allocs/op$ go test -benchRange -benchmemBenchmarkRange/*sync_test.DeepCopyMap-8 416906 2947 ns/op 0 B/op 0 allocs/opBenchmarkRange/*sync_test.RWMutexMap-8 22784 52370 ns/op 16384 B/op 1 allocs/opBenchmarkRange/*sync.Map-8 369955 3194 ns/op 0 B/op 0 allocs/op$ go test -benchAdversarialAlloc -benchmemBenchmarkAdversarialAlloc/*sync_test.DeepCopyMap-8 1875109 646 ns/op 539 B/op 1 allocs/opBenchmarkAdversarialAlloc/*sync_test.RWMutexMap-8 19454866 61.6 ns/op 8 B/op 1 allocs/opBenchmarkAdversarialAlloc/*sync.Map-8 3712470 320 ns/op 51 B/op 1 allocs/op$ go test -benchAdversarialDelete -benchmemBenchmarkAdversarialDelete/*sync_test.DeepCopyMap-8 6749067 215 ns/op 168 B/op 1 allocs/opBenchmarkAdversarialDelete/*sync_test.RWMutexMap-8 16046545 76.9 ns/op 25 B/op 1 allocs/opBenchmarkAdversarialDelete/*sync.Map-8 18678104 64.2 ns/op 18 B/op 1 allocs/op(左右滑动查看完整代码图片)如何选择Map从性能测试结果可以看出sync.Map并不是为了代替锁map的组合。它的设计是为了在某些并发场景下相对前者能有较小的性能损耗。源码文档中($GOROOT/src/sync/map.go)已经给出了sync.Map的合适场景。// The Map type is specialized. Most code should use a plain Go map instead,// with separate locking or coordination, for better type safety and to make it// easier to maintain other invariants along with the map content.//// The Map type is optimized for two common use cases: (1) when the entry for a given// key is only ever written once but read many times, as in caches that only grow,// or (2) when multiple goroutines read, write, and overwrite entries for disjoint// sets of keys. In these two cases, use of a Map may significantly reduce lock// contention compared to a Go map paired with a separate Mutex or RWMutex.(左右滑动查看完整代码图片)两种情况应该选择sync.Mapkey值一次写入多次读取(即写少读多场景)。多个goroutine的读取、写入和覆盖在不相交的key集。推荐阅读并发安全的 mapsync.Map源码分析喜欢本文的朋友欢迎关注“Go语言中文网”Go语言中文网启用微信学习交流群欢迎加微信274768166投稿亦欢迎
http://wiki.neutronadmin.com/news/58495/

相关文章:

  • 做pc网站排名网页设计与制作简介
  • 塘厦镇做网站做网站 钱
  • 十堰网站建设报价合肥外贸网站建设公司排名
  • 汽车4s销售网站模板装修网线用几类
  • 网站模版整站下载网站建设工程
  • 旅游网站开发工具伊春市住房和城乡建设局网站
  • 邵东微网站建设做网站建设推广好做吗
  • 网络维护这个工作好吗逆冬seo
  • 湖南广源建设工程有限公司网站温州营销网站公司
  • phpcms 手机网站模板私人定制网站建设
  • 有漏洞的网站企业数字化服务平台
  • 网站空间国外那个好网站开发产品描述
  • 网站建设申请理由销售流程八个步骤
  • 广告代理商公司seoaoo
  • 电脑个人网站怎么做怎么提高网站转化率
  • 网站改版规则网站搭建教室
  • 建网站外包游戏开发工程师招聘
  • 怎么做网站流量竞品分析国建设文化艺术协会网站
  • 网站名称和备案如何做百度推广的网站
  • 深圳网站建设q.479185700惠南京建设网站公司哪家好
  • 江西省城乡建设厅网站宁夏建设网站公司
  • 武夷山网站推广一个网站怎么做
  • 青岛网站建设方案维护阿里云服务器建立网站吗
  • 南阳做做网站数字营销实训总结
  • 做网站用phpwordpress ssd hdd
  • 做网站用的各种图标大全网站改版 英文
  • 网站改版的方式网站建设服务器
  • wordpress主题 视频教程深圳seo推广培训
  • 广州网站开发创意设计公司装饰网站的业务员都是怎么做的
  • 百度优化 几个网站内容一样凡科互动登录入口