开发者社区> 问答> 正文

单线程多路复用和多线程加锁的区别

看介绍说redis是单线程的,通过epool实现多路复用。由于是单线程所以对资源的访问是串行的,不会产生资源竞争。然后突然有个疑惑,既然对资源的访问是串行的,也就是说如果我某个请求要set,而前面排着K个同样要set的操作,我还是得等它们set完成我再能set。然后有几点疑问,希望大牛不吝赐教:

通过多路复用单线程串行地访问资源和多线程并发访问然后给资源加互斥锁有什么区别呢?
抛开线程创建的开销,两者的性能如何呢
golang的goroutine一定程度上减轻了线程创建的开销,高并发场景下多个goroutine访问资源时加互斥锁,和redis的单线程访问资源性能差异大吗
golang没有epool的库,或者说有个goroutine+channel还需要epool吗

展开
收起
a123456678 2016-06-23 14:54:42 4610 0
2 条回答
写回答
取消 提交回答
  • 多路复用和多线程提高并发能力的机制是不一样的。

    多路复用是通过等待IO时处理其它请求来提升效率,如果性能瓶颈在 IO 上,那么这个是很有效的。

    用银行排队来比喻,假如每个人的业务都需要柜员处理1分钟,客户处理10分钟(填单子之类的),那 IO 多路复用就是,但是等客户填单子的时候继续处理下一个人的,不在那儿等着,填好单子继续处理;多线程就是开5个柜台。

    两者都能提高并发能力,但IO多路复用的仅在瓶颈在IO的时候有效果。比如上面的例子改成柜员处理10分钟,客户1分钟,那即使柜员不等着继续处理下一个人的,也提升不了多少性能。如果是计算密集型的,瓶颈在CPU,那么使用多线程比较好。

    上面说的两种模式是可以一起用的。golang就是这个模型。io部分默认是多路复用的,同时可以起多个goroutine并发处理,所以性能很好。

    2019-07-17 19:46:20
    赞同 1 展开评论 打赏
  • 首先你要知道redis除了持久化,几乎所有操作都是在操作内存,比如像简单的set get操作都非常快,具体多快我觉得你可以自己来做一个benchmark,并不难
    如果你关注新闻的话可以知道双11阿里的交易巅峰值是14w笔/s
    这基本已经是国内it界最高的并发了(那种几亿同时在线的不算),你再去想想操作内存的时间,不考虑事务,我只把14w条数据记下来看起来并不是什么难事对不对

    一台写不过来我十台总行了吧,所以除非你的set的value本身特别大,不用担心在操作时的等待时间,就算有1w个请求过来,你还是在操作内存,严格意义上说,redis本身应对的业务场景并不是一个高并发的场景,你看一下redis本身默认的连接数设置应该也就懂了

    应对这种场景,你用多线程+锁也没有什么问题(当然性能可能会差一点点),之前tim大神做过一个memcached和redis的性能对比,虽然年代久远,不过也可以说明一些问题,要知道memcached就是多线程+锁的模型,两者看起来差别也没有太过夸张。虽然结果是redis好一些。

    看到这里你是不是觉得单线程+io复用赢了?这可真不一定。。只是在这种场景下赢了而已,本身单线程io复用和多线程+锁其实只是两种编程模型,两种模型也都是为了解决问题,哪种优要看具体的业务场景,这里还是要说了,不服跑分啊

    go的goroutine本质是green threads,runtime来调度的用户态线程,其实这种概念在其他语言里也有,只是其他语言都是以第三方库来做这件事情,go把它集成在了语言内,并且不用你自己去管理调度的事情,go语言里的实现只是让你可以更方便地写而已,所以这东西并不是银弹,不用太过迷信,go所带来的更重要的是开发效率的提升,并没有解决什么具体的问题。

    关于epoll,go语言的net库底层也是用epoll来做io复用的(仅指linux平台),epoll这个东西只是linux下的一种io复用的实现,在其他的发行版里还有其他变种,而程序员们其实不太想关心你这些事情,他们希望在linux下写的程序去freebsd还能跑,所以libevent棒棒哒,当然你写go的话,这些事情不用操心。

    2019-07-17 19:46:20
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
多IO线程优化版 立即下载
多线程 立即下载
原子变量与内存模型 立即下载

相关实验场景

更多