您的位置 首页 golang

线程安全集合

为什么需要:

设想一个系统,您需要同时从多个 线程 修改和访问数据。在相同的数据结构中!你可能会看到一个问题…..

想象一下,您正在开发一个财务平台,当同时完成多个事务时,您需要管理案例!这就像多辆汽车同时穿过一个十字路口!事故将在没有红绿灯的情况下发生……

现在这个问题可以在数据中以各种形式出现,比如:

1.同时进行多次写入。

2.同时读和写。

3.同时进行多次读取。

4.在写东西之前尝试读取。

因此,如果我们不想让内存损坏,我们需要控制和防止这些情况。一种解决方案是使用锁和 信号量 显式地编程。但这可能需要一些时间来实现,并且会使开发变得相当复杂。

另一种解决方案是使用已经有了这些实现的数据结构,通过使用它们的专用方法,我们可以在不太困难的情况下获得相同的结果。这些集合是线程安全的集合。

它们是什么:

线程安全集合是可以由多个线程同时访问的集合,同时不受争用条件限制。通过名称,我们可以直接理解它是一个集合,线程在任何时间点都可以安全地访问它。更具体地说,它可以是一个字典、一个FIFO队列、一个LIFO堆栈,它可以在不需要显式编程同步的情况下添加/删除项目。基本上,它是一种并发数据结构,更适合编程。

如何工作:

好吧,让我们回到前面提到的4个问题。有许多解决方案,但这里我们将使用下面的状态机来说明一些基本的解决方案:

首先,如果互斥锁被锁定,我们要等到它被解锁才能执行任何功能。当我们锁定互斥体时,只有锁定互斥体的线程才有权访问数据,而其他每个线程都必须等到它被解锁。

第二个问题可以简单地解决。如果我们需要写,我们首先锁定互斥,然后我们写,最后我们解锁。

当我们有多个读卡器时,只要在读卡过程中数据没有被修改,就不是什么大问题。因此,我们使用rlock为编写器锁定数据,所有的读卡器都可以读取数据,最后一个读卡器线程在完成后解锁互斥体。

第四个问题。我们需要能够检查是否有可用的值,如果有,我们读取该值。但如果它不可用,我们要等到有可用的时候!

怎么使用:

每种标准 编程语言 都有至少一个并发数据结构的实现。最简单的是FIFO队列。为了用多种语言说明一个解决方案,我们将使用生产者/消费者问题,在这个问题中,生产者的输出速度要比消费者的输出速度慢得多。这与上面提到的“在写东西之前尝试读取”问题有关。

程序将相当简单。我们将有一个每1秒产生一个值的线程。以及一个并行的消费线程,它会尽快消费一个值。

非线程安全数据的问题是,使用者在尝试使用其不能拥有的值时会创建一个错误。与此同时,它只需等待值准备好。

让我们在 java Python 和Golang 3种不同的编程语言中看到这个代码

java:

在java中你可以使用“java.util.concurrent”包。 包括:

BlockingQueue是一个阻塞FIFO队列。

Concurrent HashMap 是HashMap的并发模拟

ConcurrentSkipListMap是TreeMap的并发模拟。

在这里,您可以看到BlockingQueue的示例:

现在,如果您运行上面的代码,就会得到:

Python

在Python中我们也有一些类似的功能:

Queue 实现了FIFO,LIFO和PriorityQueue

Deques支持任何一方的线程安全,内存效率附加和弹出。

因此,让我们看看与Java相同的程序,但在Python中的实现:

通过运行上面的代码,我们自然会得到相同的结果:

GO:

但在Golang中,我们对线程安全集合采用了不同的方法。我们在go中没有基本的队列实现。 在Go中,我们使用通道使代码更容易阅读:

当然,我们得到了同样的结果:

简而言之!线程安全集合在多线程编程中非常实用,它可以促进大部分开发。

其中一个集合的最基本示例是一个队列,古典编程语言已经实现了这个队列。我们可以修改这些数据结构,读取和写入值,轻松地使用已经到位的方法,而不存在任何并发问题。

原文:

翻译:张春

文章来源:智云一二三科技

文章标题:线程安全集合

文章地址:https://www.zhihuclub.com/98420.shtml

关于作者: 智云科技

热门文章

网站地图