加入收藏 | 设为首页 | 会员中心 | 我要投稿 拼字网 - 核心网 (https://www.hexinwang.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > MySql教程 > 正文

如履薄冰:Redis懒惰删除的巨大牺牲

发布时间:2019-01-10 18:07:46 所属栏目:MySql教程 来源:老钱
导读:大家都知道 Redis 是单线程的,但是 Redis 4.0 增加了懒惰删除功能,懒惰删除需要使用异步线程对已删除的节点进行内存回收,这意味着 Redis 底层其实并不是单线程,它内部还有几个额外的鲜为人知的辅助线程。 这几个辅助线程在 Redis 内部有一个特别的名称

异步线程需要对任务队列进行轮询处理,依次从链表表头摘取元素逐个处理。摘取元素的时候也需要加锁,摘出来之后再解锁。如果一个元素都没有,它需要等待,直到主线程来唤醒它继续工作。

  1. // 异步线程执行逻辑  
  2. void *bioProcessBackgroundJobs(void *arg) {  
  3. ...  
  4.     pthread_mutex_lock(&bio_mutex[type]); // 先加锁  
  5.     ...  
  6.     // 循环处理  
  7.     while(1) {  
  8.         listNode *ln;  
  9.         /* The loop always starts with the lock hold. */  
  10.         if (listLength(bio_jobs[type]) == 0) {  
  11.             // 对列空,那就睡觉吧  
  12.             pthread_cond_wait(&bio_newjob_cond[type],&bio_mutex[type]);  
  13.             continue;  
  14.         }  
  15.         /* Pop the job from the queue. */  
  16.         ln = listFirst(bio_jobs[type]); // 获取队列头元素  
  17.         job = ln->value;  
  18.         /* It is now possible to unlock the background system as we know have  
  19.          * a stand alone job structure to process.*/  
  20.         pthread_mutex_unlock(&bio_mutex[type]); // 释放锁  
  21.         // 这里是处理过程,为了省纸,就略去了  
  22.         ...  
  23.         // 释放任务对象  
  24.         zfree(job);  
  25.         ...  
  26.         // 再次加锁继续处理下一个元素  
  27.         pthread_mutex_lock(&bio_mutex[type]);  
  28.         // 因为任务已经处理完了,可以放心从链表中删除节点了  
  29.         listDelNode(bio_jobs[type],ln);  
  30.         bio_pending[type]--; // 计数减 1  
  31.     } 

研究完这些加锁解锁的代码后,笔者开始有点担心主线程的性能。我们都知道加锁解锁是一个相对比较耗时的操作,尤其是悲观锁最为耗时。如果删除很频繁,主线程岂不是要频繁加锁解锁。

所以这里肯定还有优化空间,Java 的 ConcurrentLinkQueue 就没有使用这样粗粒度的悲观锁,它优先使用 cas 来控制并发。那就让我们就期待 Redis 在未来的版本里对它进一步改造优化吧!

(编辑:拼字网 - 核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!