【问题标题】:How to avoid mutable state (when multithreading)如何避免可变状态(多线程时)
【发布时间】:2009-06-29 08:53:23
【问题描述】:

多线程很难。您唯一能做的就是非常仔细地编程并遵循好的建议。我从这个论坛的答案中得到的一个很好的建议是避免可变状态。我知道这甚至在 Erlang 语言中也是如此。但是,如果没有严重的性能损失和大量的缓存,我看不到如何做到这一点。

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

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

【问题讨论】:

  • 不要假设你的程序应该是多线程的:如果你想让它分布式?数据结构复制在这里是一个巨大的胜利。
  • 你是对的。在我们的应用程序中,用户界面被分成一个通过 TCP 连接的瘦客户端。我们将相当一部分数据缓存在 UI 端。结果是更多的代码和更复杂的程序。

标签: multithreading language-agnostic concurrency


【解决方案1】:

并非每个算法都可以成功地并行化。

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

如果您的算法表现出结构,那么您可以用一些模式或形式(例如,宏数据流图)来表达您的计算,从而使不可变数据结构的选择变得微不足道。

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

【讨论】:

    【解决方案2】:

    通过查看 Eric Lippert 的带有不可变性标签的文章,您可以很好地开始思考不可变集合、它们适用于何处、它们如何在不需要大量复制的情况下实际工作等:

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

    【讨论】:

    【解决方案3】:

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

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

    【讨论】:

    • 你说得对,我的例子有点模糊。我会考虑并尝试提出一个更好的例子。
    【解决方案4】:

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

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

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

    【讨论】:

    • 这是一个很好的答案。非常感谢。
    【解决方案5】:

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

    【讨论】:

    • 一个构造参数? :-) 当然不是。它经常出现在我有大量密切相关的数据的情况下。事实上,你可以把它分成几部分,但我希望这会使程序代码更长更复杂。
    【解决方案6】:

    如果您确实需要更新结构,一种方法是使用单个工作线程从受互斥锁保护的固定区域获取更新请求。

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

    然后,其他线程只需要在他们主动想要更新时检查一个简单的“正在更新”互斥锁。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-19
      • 1970-01-01
      • 2021-08-06
      • 1970-01-01
      • 1970-01-01
      • 2016-01-23
      相关资源
      最近更新 更多