千家信息网

大数据中如何浅析多线程数据访问一致性问题及解决方法

发表于:2024-11-26 作者:千家信息网编辑
千家信息网最后更新 2024年11月26日,这期内容当中小编将会给大家带来有关大数据中如何浅析多线程数据访问一致性问题及解决方法,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。服务器和笔记本电脑都使用多核CPU
千家信息网最后更新 2024年11月26日大数据中如何浅析多线程数据访问一致性问题及解决方法

这期内容当中小编将会给大家带来有关大数据中如何浅析多线程数据访问一致性问题及解决方法,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

服务器和笔记本电脑都使用多核CPU,出于性能考虑,每个CPU采用了独享的Cache机制(通常有两级独享cache和一级共享cache),由此带来并发访问内存中的同一数据,在不同CPU上的可见性或一致性问题。CPU采用Cache机制带来多线程访问共享数据的一致性或数据可见性问题,是从事多线程编程的工程师们绕不过去的坎儿。

知道了问题所在,解决并发访问下数据一致性问题的方法有多种。最常用的就是加锁方式,比如C/C++下直接使用线程锁实现访问互斥,同时也能保证数据修改后的可见性。对于计数器场景,还可以采用性能更高的原子操作(其性能大约是线程锁的6倍),例如gcc内置的 __sync_add_and_fetch / __sync_fetch_and_add 或 __sync_sub_and_fetch / __sync_fetch_and_sub 等函数。另外可以利用CAS(Compare And Swap)原子操作实现无锁编程,例如gcc内置的__sync_bool_compare_and_swap 和 __sync_val_compare_and_swap。比如我们可以利用CAS实现无锁队列。

对于一个生产者和一个消费者的线程模型,使用ring buffer这样的数据结构,因不存在访问冲突的问题,可以采用无锁化编程。比如Linux内核处理ring buffer,结合使用内存屏障,可以在无锁的情况下保证数据可见性。内存屏障这块比较深奥,我在这方面没有研究和实践,在这里抛个砖就好。

针对一个线程修改数据,多个线程读取的场景,一种更为极端的无锁编程方式:不但彻底无锁(不需要CAS),而且还不使用内存屏障来保证数据可见性。这种做法显然违背了并发访问的数据一致性,但对于可接受数据最终一致的场景,这种做法是完全可行的。这是为什么呢?一个线程修改数据后,因CPU cache机制,其他线程将延迟感知到修改后的数据。根据笔者经验,这个延迟通常在1ms以内。因为没有采用加锁或内存屏障等机制,数据在多线程下的可见性存在不确定性。对于大多数数据结构(如平衡二叉树、红黑树、skiplist、hashtable等)的数据修改通常会分为多个步骤完成,在此友情提醒大家,采用这种做法的一个前提条件是,当读取线程读到部分更新后的数据时,不会导致程序逻辑错乱甚至出现崩溃等异常情况发生。平衡二叉树这样的数据结构很难采用这种编程模型(因保持平衡涉及旋转操作,需要一把大锁保护),而精心实现的skiplist和hashtable是可以做到的。

上述就是小编为大家分享的大数据中如何浅析多线程数据访问一致性问题及解决方法了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注行业资讯频道。

0