Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/302.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
奇怪的python线程输出_Python_Multithreading_Python 3.x_Locking - Fatal编程技术网

奇怪的python线程输出

奇怪的python线程输出,python,multithreading,python-3.x,locking,Python,Multithreading,Python 3.x,Locking,我得到了一个简单的python程序来分析。它工作正常,随机输出13、14和15(当然)。我明白为什么13和14是印刷出来的,但我不明白15是从哪里来的 请解释一下 from threading import Thread import random import time import sys def rwait(): amt = random.uniform(0.01,0.1) time.sleep(amt) x = 0 key = True def lockx():

我得到了一个简单的python程序来分析。它工作正常,随机输出13、14和15(当然)。我明白为什么13和14是印刷出来的,但我不明白15是从哪里来的

请解释一下

from threading import Thread
import random
import time
import sys

def rwait():
    amt = random.uniform(0.01,0.1)
    time.sleep(amt)

x = 0

key = True

def lockx():
    global key
    while not key:
        time.sleep(0)
    rwait()
    key = False

def unlockx():
    global key
    key = True

def A():
    global x
    rwait()
    lockx()
    reg = x
    reg = reg+1
    rwait()
    x = reg
    unlockx()

def B():
    global x
    rwait()
    lockx()
    reg = x
    reg = reg+2
    rwait()
    x = reg
    unlockx()

def main():
    global x
    x = 12
    p1 = Thread(target=B)
    p1.start()
    A()
    p1.join()
    print("x=",x)


for k in range(20):
    main()

可能发生三种不同的情况:

  • 线程A和B在更改之前读取
    x
    ,然后

    • 线程A写入其结果(13),然后

    • 线程B写入其结果(14)

    而第二个线程将要写入的线程将获胜

  • 线程A或B首先读取
    x
    ,然后在另一个线程读取之前写入。结果:15,A读12,加1写13,然后B读13写15,反之亦然


    • 可能发生三种不同的情况:

      • 线程A和B在更改之前读取
        x
        ,然后

        • 线程A写入其结果(13),然后

        • 线程B写入其结果(14)

        而第二个线程将要写入的线程将获胜

      • 线程A或B首先读取
        x
        ,然后在另一个线程读取之前写入。结果:15,A读12,加1写13,然后B读13写15,反之亦然


      您已经在这里演示了一个经典的并发问题。两个写入程序同时工作,因此可能会覆盖另一个写入的数据

      如果收到13,则线程
      A
      在线程
      B
      写入其结果之前读取,而
      A
      B
      写入其结果之后写入

      如果收到14,则线程
      B
      在线程
      A
      写入其结果之前读取,而
      B
      A
      写入其结果之后写入

      如果收到15,则一个线程在另一个线程写入其结果后读取(以及计算和写入)。此时无法确定两个线程的顺序


      然而,更有趣的问题是,为什么锁定机制(
      lockx
      /
      unlockx
      )显然不起作用。如果它能工作,那么结果总是得到15。

      您已经在这里演示了一个经典的并发问题。两个写入程序同时工作,因此可能会覆盖另一个写入的数据

      如果收到13,则线程
      A
      在线程
      B
      写入其结果之前读取,而
      A
      B
      写入其结果之后写入

      如果收到14,则线程
      B
      在线程
      A
      写入其结果之前读取,而
      B
      A
      写入其结果之后写入

      如果收到15,则一个线程在另一个线程写入其结果后读取(以及计算和写入)。此时无法确定两个线程的顺序


      然而,更有趣的问题是,为什么锁定机制(
      lockx
      /
      unlockx
      )显然不起作用。如果它能工作的话,你总是会得到15个。你的函数名似乎暗示它们正在执行锁定,而事实并非如此。这有两个原因:

      • 键的访问不保证原子性
      • 即使是,在读取
        且其值为
        True
        的时间与使用该键并将其设置为
        False
        的时间之间也存在竞争
      结果,您的两个线程最终以不同步的方式修改共享(在本例中为全局)状态。因此,三种情况中的任何一种都是可能的:

    • x
      仅递增1-
      B
      A
      读取
      x
      后,但在递增的值被存储回之前,已完全执行
    • x
      仅增加2-与上面的情况相同,并反转
      A
      B
    • x
      增加3-
      A
      B
      分别在
      B
      A
      之前执行
    • 要正确同步两个线程,必须使用锁定。下面是对代码的修改,使用线程提供的功能:

      from threading import Thread, Lock
      
      x = 0
      
      lock = Lock()
      
      def lockx():
          global lock
          lock.acquire()
      
      def unlockx():
          global lock
          lock.release()
      
      def A():
          global x
          lockx()
          reg = x
          reg = reg+1
          x = reg
          unlockx()
      
      def B():
          global x
          lockx()
          reg = x
          reg = reg+2
          x = reg
          unlockx()
      
      def main():
          global x
          x = 12
          p1 = Thread(target=B)
          p1.start()
          A()
          p1.join()
          print("x=",x)
      
      for k in range(20):
          main()
      

      您的函数名似乎暗示它们正在执行锁定,但事实并非如此。这有两个原因:

      • 键的访问不保证原子性
      • 即使是,在读取
        且其值为
        True
        的时间与使用该键并将其设置为
        False
        的时间之间也存在竞争
      结果,您的两个线程最终以不同步的方式修改共享(在本例中为全局)状态。因此,三种情况中的任何一种都是可能的:

    • x
      仅递增1-
      B
      A
      读取
      x
      后,但在递增的值被存储回之前,已完全执行
    • x
      仅增加2-与上面的情况相同,并反转
      A
      B
    • x
      增加3-
      A
      B
      分别在
      B
      A
      之前执行
    • 要正确同步两个线程,必须使用锁定。下面是对代码的修改,使用线程提供的功能:

      from threading import Thread, Lock
      
      x = 0
      
      lock = Lock()
      
      def lockx():
          global lock
          lock.acquire()
      
      def unlockx():
          global lock
          lock.release()
      
      def A():
          global x
          lockx()
          reg = x
          reg = reg+1
          x = reg
          unlockx()
      
      def B():
          global x
          lockx()
          reg = x
          reg = reg+2
          x = reg
          unlockx()
      
      def main():
          global x
          x = 12
          p1 = Thread(target=B)
          p1.start()
          A()
          p1.join()
          print("x=",x)
      
      for k in range(20):
          main()
      

      你认为你的程序到底在做什么?@MichaelFoukarakis同时运行def A()和def B(),并根据定义过程将1或2添加到12。我是python的新手,尤其是多线程。线程通常不能保证并行运行
      a()
      B()
      ——线程本身提供并发性,但不能提供并行性。如果你想以1或2来修改
      x
      ,你需要修改你的代码。你认为你的程序到底在做什么?@MichaelFoukarakis同时运行def A()和def B(),并根据定义过程将1或2添加到12。我是python的新手,尤其是multith