如何避免可变状态(多线程时)

时间:2009-06-29 08:53:23

标签: multithreading language-agnostic concurrency

多线程很难。你唯一能做的就是仔细编程并遵循好的建议。我从这个论坛的答案得到的一个很好的建议是避免可变状态。据我所知,这甚至在Erlang语言中得到了强制执行。但是,如果没有严重的性能损失和大量的缓存,我就无法看到如何做到这一点。

例如。你有一个很大的对象列表,每个对象包含很多属性;换句话说:一个大型数据结构。假设你有一堆线程,他们都需要访问和修改列表。 如何在没有共享内存的情况下完成此操作而无需在每个线程中缓存整个数据结构?

更新:在阅读了目前为止的反应之后,我想更加强调性能。您是否认为复制相同的数据会使程序比使用共享内存慢?

6 个答案:

答案 0 :(得分:2)

并非每种算法都能以成功的方式并行化。

如果你的程序没有展示任何“并行结构”,那么你就注定要使用锁定和共享的可变结构。

如果您的算法展示了结构,那么您可以根据某些模式或形式(例如,宏数据流图)来表达您的计算,这使得选择不可变数据结构变得微不足道。

所以:根据算法的结构来考虑,而不是根据要使用的数据结构的属性。

答案 1 :(得分:2)

通过查看Eric Lippert标记为不变性的文章,您可以在思考不可变集合,适用它们,如何实际工作而不需要大量复制等方面有一个良好的开端:

http://blogs.msdn.com/ericlippert/archive/tags/Immutability/default.aspx

答案 2 :(得分:1)

我想第一个问题是:为什么他们需要修改列表?他们是否有可能将更改作为修改列表返回而不是实际修改共享列表?他们可以使用看起来像是原始列表的可变版本的列表,但实际上只是本地可变吗?您是在更改列表中的元素,还是只更改这些元素的属性?

这些只是问题而不是答案,但我试图鼓励您以不同的方式思考问题。将大局视为您想要实现的任务,而不是考虑以正常的命令式,可变的方式解决它的方式。改变你对问题的看法是非常困难的,但你可能会发现你得到了一些很棒的“啊哈!”时刻:))

答案 3 :(得分:1)

使用多个线程和大量数据时存在许多缺陷。如果你能设法遵循指南,那么避免可变状态的建议就是试着让你的生活更轻松(即如果你没有可变状态,那么多线程会更容易)。

如果您需要修改大量数据,那么您可能无法避免可变状态。另一种方法是将数据分区为块,每个块都传递给一个线程进行操作。可以处理该块然后传回,然后控制器可以在必要时执行更新。在这种情况下,您已从线程中删除了可变状态。

如果无法做到这一点,并且每个线程都需要对完整列表的更新访问权限(即它可以随时更新列表中的任何项目)那么您将获得很多乐趣,以确保您获得了锁定策略和并发问题排序。我确信有些情况需要这样做,避免可变状态的设计模式可能不适用。

答案 4 :(得分:1)

使用不可变数据对象是一个很大的帮助。 修改列表听起来像构造的参数,但要考虑不知道列表的粒度方法。

答案 5 :(得分:1)

如果你真的需要更新结构,一种方法是使用一个工作线程从一个互斥锁的固定区域获取更新请求。

如果你聪明,你可以在不影响任何“阅读”的情况下更新结构 线程(例如,如果要添加到数组的末尾,则执行所有工作以添加新结构,但仅在最后一条指令中增加NoOfMembers计数 - 读取线程不应该看到新条目,直到您执行这个 - 或者 - 将您的数据排列为结构引用数组 - 当您想要更新结构时,复制当前成员,更新它,然后作为最后一个操作替换数组中的引用)

其他线程只需要在他们真正想要更新时才检查一个简单的“progess”中的“mutex更新”。