Python线程-关键部分

2024-05-17 17:14:48 发布

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

线程的“关键部分”是什么(在Python中)?

A thread enters the critical section by calling the acquire() method, which can either be blocking or non-blocking. A thread exits the critical section, by calling the release() method.

-Understanding Threading in Python, Linux Gazette

还有,锁的目的是什么?


Tags: thewhichbysectionblocking线程threadcan
3条回答

"critical section"是一段代码,为了确保正确性,必须确保一次只能有一个控制线程在该部分中。一般来说,您需要一个关键部分来包含引用,这些引用将值写入内存中,以便在多个并发进程之间共享。

代码的关键部分是一次只能由一个线程执行的部分。以聊天服务器为例。如果每个连接(即每个最终用户)都有一个线程,那么一个“关键部分”是假脱机代码(向所有客户端发送传入消息)。如果不止一个线程试图一次假脱机一条消息,您将得到BfrIToS mANtwD pioemessages交织,这显然是没有好处的。

锁可以用来同步对关键部分(或一般资源)的访问。在我们的聊天服务器示例中,锁就像一个锁着的房间,里面有一台打字机。如果其中有一个线程(键入消息),则其他线程无法进入房间。一旦第一根线完成,他就打开房间,离开。然后另一根线可以进入房间(锁住它)。”“锁”的意思是“我得到房间”

其他人给出了很好的定义。下面是一个典型的例子:

import threading
account_balance = 0 # The "resource" that zenazn mentions.
account_balance_lock = threading.Lock()

def change_account_balance(delta):
    global account_balance
    with account_balance_lock:
        # Critical section is within this block.
        account_balance += delta

假设+=运算符由三个子组件组成:

  • 读取当前值
  • 将RHS添加到该值中
  • 将累积值写回LHS(从技术上讲,是用Python术语绑定的)

如果没有with account_balance_lock语句,并且并行执行两个change_account_balance调用,则可能会以危险的方式交错这三个子组件操作。假设您同时调用change_account_balance(100)(AKA pos)和change_account_balance(-100)(AKA neg)。这可能会发生:

pos = threading.Thread(target=change_account_balance, args=[100])
neg = threading.Thread(target=change_account_balance, args=[-100])
pos.start(), neg.start()
  • 位置:读取当前值->;0
  • 负:读取当前值->;0
  • 位置:将当前值添加到读取值->;100
  • 负:将当前值添加到读取值->;-100
  • pos:写入当前值->;帐户余额=100
  • 负:写入当前值->;帐户余额=-100

因为您没有强制操作以离散块的形式发生,所以可以有三种可能的结果(-100,0,100)。

with [lock]语句是一个单独的、不可分割的操作,它说:“让我成为执行此代码块的唯一线程。如果有其他东西正在执行,那就很酷了——我会等的。”这确保了对account_balance的更新是“线程安全”(并行安全)的。

注意:此架构有一个警告:每次要操作account_balance以使代码保持线程安全,您必须记住获取account_balance_lock(通过with)。有办法让它不那么脆弱,但这是另一个问题的答案。

编辑:回顾过去,可能需要指出的是,with语句隐式调用锁上的阻塞acquire——这是上述线程对话框的“我将等待”部分。相比之下,一个非阻塞获取说,“如果我不能立即获取锁,让我知道”,然后依赖你检查你是否得到锁。

import logging # This module is thread safe.
import threading

LOCK = threading.Lock()

def run():
    if LOCK.acquire(False): # Non-blocking -- return whether we got it
        logging.info('Got the lock!')
        LOCK.release()
    else:
        logging.info("Couldn't get the lock. Maybe next time")

logging.basicConfig(level=logging.INFO)
threads = [threading.Thread(target=run) for i in range(100)]
for thread in threads:
   thread.start()

我还想补充一点,锁的主要目的是保证获取的原子性(线程间acquire的不可分割性),而简单的布尔标记不能保证这一点。原子操作的语义可能也是另一个问题的内容。

相关问题 更多 >