首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python:通过多个线程并发访问函数,而不使用锁机制

Python:通过多个线程并发访问函数,而不使用锁机制
EN

Stack Overflow用户
提问于 2013-03-14 06:15:46
回答 4查看 3.6K关注 0票数 3

当多个线程访问同一个函数时,我们是否需要显式地实现机制。

我有一个使用线程的程序。有两个线程,t1t2t1用于add1()t2用于线程的subtract1().Both并发访问相同的函数myfunction(caller,num)

1.我使用变量functionLock**.在给定的程序中定义了一个简单的锁机制这是可靠的还是我们需要修改它。**

代码语言:javascript
复制
import time, threading

functionLock = '' # blank means lock is open        

def myfunction(caller,num):
    global functionLock
    while functionLock!='': # check and wait until the lock is open
        print "locked by "+ str(functionLock)
        time.sleep(1)

    functionLock = caller # apply lock

    total=0
    if caller=='add1':
        total+=num
        print"1. addition finish with Total:"+str(total)
        time.sleep(2)
        total+=num
        print"2. addition finish with Total:"+str(total)
        time.sleep(2)
        total+=num
        print"3. addition finish with Total:"+str(total)

    else:
        time.sleep(1)
        total-=num
        print"\nSubtraction finish with Total:"+str(total)

    print '\n For '+caller+'() Total: '+str(total)

    functionLock='' # release the lock


def add1(arg1, arg2):

    print '\n START add'
    myfunction('add1',10)
    print '\n END add'        


def subtract1():

  print '\n START Sub'  
  myfunction('sub1',100)   
  print '\n END Sub'


def main():

    t1 = threading.Thread(target=add1, args=('arg1','arg2'))
    t2 = threading.Thread(target=subtract1)
    t1.start()
    t2.start()


if __name__ == "__main__":
  main()

产出如下:

代码语言:javascript
复制
START add
START Sub
1. addition finish with Total:10
locked by add1
locked by add1
2. addition finish with Total:20
locked by add1
locked by add1
3. addition finish with Total:30 
locked by add1
 For add1() Total: 30
 END add
Subtraction finish with Total:-100
 For sub1() Total: -100
 END Sub

2.我们可以不使用锁吗?

即使我不使用上述程序中定义的锁机制,从线程t1和t2来看,结果也是一样的。这是否意味着,当多个线程访问同一个函数时,python自动实现锁。

在上述程序中不使用锁functionLock的程序输出

代码语言:javascript
复制
START add
START Sub
1. addition finish with Total:10
Subtraction finish with Total:-100
For sub1() Total: -100
END Sub
2. addition finish with Total:20
3. addition finish with Total:30
For add1() Total: 30
END add

谢谢!

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-03-14 17:44:22

除了这个线程上关于忙于等待变量的其他注释之外,我想指出的是,您没有使用任何类型的原子交换可能会导致并发错误。即使您的测试执行不会导致出现这些事件,但如果在不同时间执行足够多的重复,则可能会出现以下事件序列:

线程1执行while functionLock!=''并获取False。然后,Thread#1被中断(优先执行其他东西),线程#2执行同一行,while functionLock!=''也得到False。在本例中,两个线程都进入了关键部分,这显然不是您想要的。特别是,在线程修改total的任何行中,结果可能都不是您预期的结果,因为这两个线程可以同时位于该部分。请参见以下示例:

total10。为了简单起见,假设num总是1。Thread#1执行total+=num,它由三个操作组成:(i)加载total的值,(ii)添加num,(iii)将结果存储在total中。如果在(i)之后,Thread#1被抢占,Thread#2执行total-=num,则total设置为9。然后,Thread#1恢复。但是,它已经加载了total = 10,因此它添加了1并将11存储到total变量中。这有效地改变了Thread#2在无操作中的减量操作.

注意,在@ron链接的维基百科文章中,代码使用了一个xchg操作,它原子地用变量交换寄存器。这对于修正锁是至关重要的。总之,如果您想避开难以调试的并发错误,永远不要将自己的锁作为原子操作的替代。

编辑我刚刚注意到,实际上total是代码中的一个局部变量,所以这是不可能发生的。但是,我认为您没有意识到这是代码完美工作的原因,因为您肯定“这是否意味着当多个线程访问同一个函数时python自动实现锁”,这不是真的。请尝试将global total添加到myfunction的开头,并多次执行线程,您将在输出中看到错误。/edit

票数 1
EN

Stack Overflow用户

发布于 2013-03-14 06:19:44

虽然我对Python不太了解,但我想说,这与任何其他语言一样:

只要没有在函数之外声明并因此可以在线程之间共享的变量,就不应该需要锁。你的功能似乎不是这样的。

但是,控制台的输出可能会被混淆。

票数 1
EN

Stack Overflow用户

发布于 2013-03-14 06:20:31

当您认为正在编写的代码是关键部分代码时,您需要锁定,即代码段是否正在修改线程之间的共享状态,如果不是,则不需要担心锁定。

是否应该锁定方法是一种设计选择,理想情况下,您应该将锁锁定为更接近线程的共享状态访问。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15402452

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档