python - 互斥体适用于快速的单一作者/缓慢的读者(cpython)?

标签 python multithreading mutex shared-memory

在我的应用程序中,我有一个线程对日志行执行非常快速的处理以生成一个浮点值。通常只有一个其他线程每隔一段时间对值执行缓慢读取。每隔一段时间,其他线程就会来来去去,并对这些值执行一次性读取。

我的问题是关于互斥体的必要性(在 cpython 中),对于这种数据只是最新可用数据的特定情况。它不是必须与其他任何内容(甚至是同时写入的其他字段)同步的临界值。只是简单地......当它存在时它的值(value)是什么。

也就是说,我知道我可以很容易地添加一个锁(或一个读者/写锁)来保护值的更新,但我想知道在一个过程中快速连续获取/释放的开销是否整个日志(比方说平均 5000 行)仅仅“适本地”共享资源是不值得的。

基于 What kinds of global value mutation are thread-safe? 上的文档,这些赋值应该是原子操作。

这是逻辑的基本示例:

import time
from random import random, choice, randint
from threading import Thread 

class DataStructure(object):
    def __init__(self):
        self.f_val = 0.0
        self.s_val = ""

def slow_reader(data):
    """ 
    Loop much more slowly and read values 
    anywhere between 1 - 5 second intervals
    """
    for _ in xrange(10):

        f_val = data.f_val 
        # don't care about sync here
        s_val = data.s_val

        print f_val, s_val

        # in real code could be even 30 or 60 seconds
        time.sleep(randint(1,3))

def fast_writer(data):
    """ Update data extremely often """
    for _ in xrange(20000):
        f_val, s_val = do_work()

        data.f_val = f_val
        # don't care about sync here
        data.s_val = s_val 


FLOAT_SRC = [random()*100 for _ in xrange(100)]
STR_SRC = ['foo', 'bar', 'biz', 'baz']

def do_work():
    time.sleep(0.001)
    return choice(FLOAT_SRC), choice(STR_SRC)


if __name__ == "__main__":

    data = DataStructure()

    threads = [
        Thread(target=slow_reader, args=(data,)),
        Thread(target=fast_writer, args=(data,)),
    ]

    for t in threads:
        t.daemon=True
        t.start()

    for t in threads:
        t.join()

这表示快速日志解析器(实际上是通过 PIPE 读取)在每一行上工作,而慢速周期性读取器获取当时的当前值。在任何时候,另一个一次性读取线程可能会来来去去从数据结构中获取相同的值。

这是根本不需要 cpython 中的互斥量的情况吗?

编辑

再澄清一点……我什至不需要浮点和字符串字段与上次写入同步。如果调度程序决定在 float 和 string 读取之间切换上下文是可以的。我只是想知道我是否需要锁的开销来简单地及时读取在任何时刻分配的任何值。

我担心的是,作者将在一个极快的操作上循环,锁定和解锁一个通常没有竞争的锁。

有效地假设这就是我在阅读器中所关心的:

def slow_reader(data):
    for _ in xrange(10):
        f_val = data.f_val 
        print f_val
        time.sleep(randint(1,3))

最佳答案

进行并发访问时需要一个互斥体:

  • 在复合值上,并且这些访问之一必须以原子方式修改多个位置的值;
  • 在简单值上,并且这些访问中至少有两个是写的。

在您的示例中,该值是复合值(2 个字段),并且修改在多个点(这 2 个字段)上运行,因此您应该放置一个互斥锁以确保不会在两次修改之间安排读取器.

编辑:如果读者不关心字段是否同步,那么您就不需要互斥体。

关于python - 互斥体适用于快速的单一作者/缓慢的读者(cpython)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13256735/

相关文章:

python - 检查并转换多索引类型

python - 如何在 Python 中获取最新的目录

Python多处理需要更长的时间

python - 能够绘制为列表,无法绘制为 Pandas 系列

c# - 从多个线程写入 bool 变量在 C# 中安全吗?

java - JavaFx并发事件

用于无限数据输入(流)的python线程和队列

c - 使用互斥锁时, "printf"输出两次(或更多?我不确定)?

c# - 使用 Mutex 运行应用程序的单个实例

multithreading - 互斥锁 : what does "blocking" mean?