【问题标题】:What is Atomic Operations in Python?什么是 Python 中的原子操作?
【发布时间】:2019-04-10 01:59:34
【问题描述】:

我是 Python 的初学者。现在我阅读了有关线程的内容,但我有一些问题。

IMO 原子操作 (AO) = 最简单的操作。 dev 中最简单的操作是a = 1。但是我确实看过文章(http://preshing.com/20130618/atomic-vs-non-atomic-operations/),我的印象是它没有最简单的操作\AO。作者告诉我们这个操作分为两个操作,这个操作不是AO。这个操作是AO,它必须有另一种类型。但我必须说他讲述了 C/C++ 和字节码,我认为在 Python 中也是如此。我如何理解这取决于类型,也许还有编译器。但是 Python 是动态类型的语言。它没有类型。

我决定向社区提出以下问题:

  1. 什么是 Python 中的原子操作?

  2. Python中有哪些操作是AO?

如果简单操作不简单,那我就不明白什么是原子操作了。

【问题讨论】:

    标签: python python-multithreading


    【解决方案1】:

    Python 文档的常见问题解答似乎在What kinds of global value mutation are thread-safe? 下对这个问题有一个很好的答案

    我希望您了解本地堆栈变量或特定线程的私有变量(不会出现线程安全问题)与全局或共享变量之间的区别。

    【讨论】:

    • 非常感谢...我忘记了 Python 常见问题解答... :) 我不确定。什么意思?
    • 好吧,如果你在一个方法中有一个局部变量,例如,你永远不必担心原子地修改它,因为没有其他线程会看到该变量的同一个副本。您在代码中本地创建且从不分配给全局变量的对象的属性也是如此。这没什么大不了的...有时您可以知道没有其他线程能够访问特定变量。
    • 是的,我知道。我对“本地 stack 变量”感到困惑,我仍然不太了解术语,但我研究了它。感谢您的解释。我更担心全局变量。
    【解决方案2】:

    我开发了一个工具来实现多线程或多进程环境的共享原子性。

    借助多处理/多线程共享ctypes,我们实现了共享变量和数组。但是同步可以通过锁来实现。这个包提供了第二种方式来访问那些具有原子操作的原始 ctypes。可以在python 3.0以上版本使用到最新的3.11

    要求,

    Linux/MacOSX

    该软件包需要在 Linux 平台上安装 libatomic cffi ==1.15 在 Linux/MacOSX 平台上编译通过 gcc >= 4.8 以包含原子 API。

    窗户 待定

    安装

    要安装 shared_atomic,请使用 pip:

    pip install shared_atomic

    用法

    使用 ctypes 加载已编译的 .so 文件

      import ctypes
    
      atomic = ctypes.CDLL(‘shared_atomic.cpython-36m-darwin.so’)
    

    在多线程情况下:

      #get pointer address by ctypes.byref
    
      v = ctypes.c_size_t(2 ** 63 - 1)
    
      vref = ctypes.byref(v)
    
      #start multiple threads
    
      threadlist=[]
    
      for i in range(10000):
    
         threadlist.append(Thread(target=atomic.size_t_sub_and_fetch, args=(vref, ctypes.c_size_t(100))))
      for i in range(10000):
    
              threadlist[i].start()
      for i in range(10000):
    
              threadlist[i].join()
    

    在多重加工条件下:

    #get pointer address by ctypes.byref
    
         v = multiprocessing.Value(ctypes.c_size_t, 2 ** 63 - 1, lock=False)
    
         vref = ctypes.byref(v)
    
    #start multiple processes
    
         processlist = []
    
         for i in range(10000):
    
            processlist.append(Process(target=atomic.size_t_sub_and_fetch, args=(vref, ctypes.c_size_t(100))))
         for i in range(10000):
    
            processlist[i].start()
         for i in range(10000):
    
            processlist[i].join()
    

    目前

    concurrent.futures.ProcessPoolExecutor

    concurrent.futures.ThreadPoolExecutor

    不能用于启动多次执行,因为cdll函数不能被pickle序列化。

    源代码仓库:

    https://github.com/irvinren/shared_atomic.git
    
    https://gitee.com/irvinren/shared_atomic.git
    

    有关文档,请访问:

    https://shared-atomic.readthedocs.io/en/latest/
    

    该项目在 GPL v3.0 下获得许可

    【讨论】:

      猜你喜欢
      • 2017-11-19
      • 2013-07-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多