真的需要时线程锁?

2024-06-28 20:32:46 发布

您现在位置:Python中文网/ 问答频道 /正文

我一直在大量使用线程(并行处理)和锁(防止同时操作共享对象)。由于我正在以并行线程的极高处理速度编写代码,接收数据并填充共享数据缓冲区,我想知道什么时候真的需要锁?你知道吗

  • 写入共享对象
  • 读取共享对象
  • 更新共享对象的内容

我知道第三种情况主要很关键(给出了著名的线程和锁的“增量计数器”示例)。但在其他情况下我也应该使用锁吗?你知道吗

在我的特殊情况下,它是关于一个用作数据缓冲区的数据帧。我想:

  • 向其中添加新数据
  • 从中获取数据
  • 从中删除数据(创建循环缓冲区)

下面的最小工作示例(MWE)用线程显示了这个进程,但是为了简单起见,这里是按顺序处理的,并且进程之间有密集的锁。虽然这是一个非常谨慎的方法,但我想有些获取/释放锁的步骤可能会被放弃?但由于pandas在附加对象时正在复制对象,所以我不能100%确定是否要删除这些锁。你知道吗

有没有人对此进行过深入的测试,或者有没有人对此有过经验?你知道吗


中全景:

import pandas as pd
import threading

thread_lock = threading.Lock()

df_data_buffer = pd.DataFrame({"key" : []})

def add_data_to_buffer(df_data_ingestion):        
    global df_data_buffer
    thread_lock.acquire()
    df_data_buffer = df_data_buffer.append(df_data_ingestion)
    thread_lock.release()

def get_data_from_buffer(key):
    thread_lock.acquire()
    df_data_buffer.reset_index(inplace=True, drop=True) #required for proper dropping by index
    df_extracted = df_data_buffer.loc[df_data_buffer["key"] == key].copy()
    thread_lock.release()
    drop_data(df_extracted.index)
    return df_extracted

def drop_data_from_buffer(df_index):
    global df_data_buffer
    thread_lock.acquire()
    df_data_buffer.drop(df_index, inplace=True)
    thread_lock.release()
    return True


df_data1 = pd.DataFrame({"key" : [1]})
t_add_data1 = threading.Thread(target=add_data, args=[df_data1])
t_add_data1.start()
t_add_data1.join()
print "*"*10, 1, "*"*10
print df_data_buffer

df_data2 = pd.DataFrame({"key" : [2]})
t_add_data2 = threading.Thread(target=add_data, args=[df_data2])
t_add_data2.start()
t_add_data2.join()
print "*"*10, 2, "*"*10
print df_data_buffer

key=1
df_data_extracted = get_data(key)
print "*"*10, "extract", "*"*10
print "df_data_extracted\n", df_data_extracted
print "df_data_buffer\n", df_data_buffer

print "*"*10, 3, "*"*10
df_data3 = pd.DataFrame({"key" : [3]})
t_add_data3 = threading.Thread(target=add_data, args=[df_data3])
t_add_data3.start()
t_add_data3.join()
print df_data_buffer

输出:

********** 1 **********
   key
0  1.0
********** 2 **********
   key
0  1.0
1  2.0
********** extract **********
df_data_extracted
   key
0  1.0
df_data_buffer
   key
1  2.0
********** 3 **********
   key
0  2.0
1  3.0

Tags: 数据对象keyaddlockdfdataindex
1条回答
网友
1楼 · 发布于 2024-06-28 20:32:46

你选择什么对你很重要。执行读取时,是否需要最新数据。例如,您可以选择在读取数据帧时不包含锁,而在一些计算之后重新分配数据帧时只包含锁。但是,您似乎需要完全的一致性保证,而您当前的锁定规程可以很好地使用这种保证。此外,当从多个线程写入数据时,pandas DataFrame没有内部一致性保证,因此必须在这样做时锁定。你知道吗

但是,您还必须意识到cpython实现使用了^{}或全局解释器锁,只允许在任何给定时间执行一个python“线程”。要获得实际的并行性,必须使用从GIL中解放出来的^{}。由于这个事实,我怀疑上面的代码执行速度是否比在单个线程中运行这个操作快。你知道吗

相关问题 更多 >