当前位置:  开发笔记 > 编程语言 > 正文

Python线程 - 关键部分

如何解决《Python线程-关键部分》经验,为你挑选了2个好方法。

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

线程通过调用acquire()方法进入临界区,该方法可以是阻塞的也可以是非阻塞的.线程通过调用release()方法退出临界区.

- 在Python,Linux Gazette中理解线程

另外,锁的目的是什么?



1> zenazn..:

代码的关键部分是一次只能由一个线程执行的代码.以聊天服务器为例.如果每个连接都有一个线程(即每个最终用户),则一个"关键部分"是假脱机代码(向所有客户端发送传入消息).如果多个线程一次尝试假脱机,你会得到BfrIToS mttwD PIoEmesCEsaSges交织在一起,这显然是不好的.

锁可以用于同步对关键部分(或一般资源)的访问.在我们的聊天服务器示例中,锁就像一个带有打字机的锁定房间.如果一个线程在那里(键入消息),没有其他线程可以进入房间.第一个线程完成后,他解锁房间并离开.然后另一个线程可以进入房间(锁定它)."获取"锁只意味着"我得到了房间".


试着告诉Erlang家伙.在许多编程语言中它可能是错误的,但由于它如此常见(并提供了这样一个有用的例子),我决定采用它.在关于连接池的问题中,我会说别的:)

2> cdleary..:

其他人给出了非常好的定义.这是经典的例子:

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()

pos:读取当前值 - > 0

neg:读取当前值 - > 0

pos:将当前值添加到读取值 - > 100

neg:将当前值添加到读取值 - > -100

pos:写入当前值 - > account_balance = 100

neg:写入当前值 - > account_balance = -100

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

with [lock]语句是一个单独的,不可分割的操作,它说:"让我成为执行这段代码的唯一线程.如果还有别的东西正在执行,那很酷 - 我会等." 这确保了对account_balance"线程安全"(并行安全)的更新.

注意:这个模式有一个警告:每次你想操纵代码以保持线程安全时,你必须记住获取account_balance_lock(via with)account_balance.有办法让这个不那么脆弱,但这是另一个问题的答案.

编辑:回想起来,重要的是要提到该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跨线程的不可分割性),这是一个简单的布尔标志无法保证的.原子操作的语义可能也是另一个问题的内容.

推荐阅读
linjiabin43
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有