【问题标题】:what's the best practice for accessing shared data with python multi-threading使用 python 多线程访问共享数据的最佳实践是什么
【发布时间】:2017-10-27 17:56:41
【问题描述】:

在python多线程中,有一些可以访问的原子类型 由多个没有保护的线程(列表、字典等)。还有一些类型需要锁保护。

我的问题是:

  1. 我在哪里可以找到列出所有原子类型的官方文档,我可以在谷歌上搜索一些答案,但它们不是“官方”且已过时。

  2. 有些书建议我们应该用锁保护所有共享数据,因为原子类型可能因为非原子,我们不应该依赖它。这个对吗? 因为锁肯定有开销,即使是大程序,这个开销也可以忽略不计吗?

【问题讨论】:

    标签: python multithreading


    【解决方案1】:

    用于使操作原子化。这意味着只有一个线程可以访问某些资源。 使用许多锁会导致您的应用程序失去线程化的好处,因为只有一个线程可以访问资源。

    如果你仔细想想,它没有多大意义。它会让你的程序变慢,因为 python 需要管理和线程之间的上下文切换。

    使用线程时,您应该尽可能尽量减少锁的数量。尽可能尝试使用局部变量。让你的函数做一些工作,并返回一个值而不是更新现有的值。 然后你可以创建一个队列并收集结果。

    除了锁,还有信号量。这些基本上是锁,只有有限数量的线程可以使用它:

    semaphore 管理一个内部计数器,该计数器在每次调用 acquire() 时递减,并在每次 release() 调用时递增。计数器永远不会低于零;当acquire() 发现它为零时,它会阻塞,等待其他线程调用release()。

    Python 有一个很好的 threading module 文档。


    这是一个使用单线程与 3 线程测试的虚拟函数的小示例。注意Lock对运行时间的影响:

    线程(无锁)持续时间:1.0949997901

    线程(带锁)持续时间:3.1289999485

    单线程持续时间:3.09899997711

    def work():
        x = 0
        for i in range(100):
            x += i
        lock.acquire()
        print 'acquried lock, do some calculations'
        time.sleep(1)
        print x
        lock.release()
        print 'lock released'
    

    【讨论】:

      【解决方案2】:

      我想你正在寻找这个link

      从上面的链接:

      一个作用于共享内存的操作是原子的,如果它在一个 相对于其他线程的单步。当原子存储 在共享变量上执行,没有其他线程可以观察到 修改半完成。当一个原子加载在一个 共享变量,它读取整个值,因为它出现在单个 这一刻。非原子加载和存储不会使那些 保证。

      对列表的任何操作都不是原子操作,因此需要特别注意使用锁、事件、条件或信号量等使其线程安全。

      例如,您可以查看解释 how list are thread safe 的答案。

      【讨论】:

      • 我认为很难知道一步会完成什么操作。有很多类型。我确实可以在需要时检查每种类型,但正如我在问题中提到的那样,我得到的答案不是官方的,而且大部分时间没有数据,没有版本信息。
      猜你喜欢
      • 1970-01-01
      • 2014-06-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-23
      • 2021-05-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多