Python Can';我不理解TensorOverflow train.QueueRunner的结果

Python Can';我不理解TensorOverflow train.QueueRunner的结果,python,multithreading,tensorflow,queue,Python,Multithreading,Tensorflow,Queue,对不起,我是TensorFlow的初学者。下面是TensorFlow的代码,它使用两个线程独立地排队和出列 import tensorflow as tf Q = tf.compat.v1.FIFOQueue(1000, tf.float32) var = tf.Variable(0.0) data = tf.compat.v1.assign_add(var, tf.constant(1.0)) en_q = Q.enqueue(data) qr = tf.train.QueueRunner(

对不起,我是TensorFlow的初学者。下面是TensorFlow的代码,它使用两个线程独立地排队和出列

import tensorflow as tf

Q = tf.compat.v1.FIFOQueue(1000, tf.float32)
var = tf.Variable(0.0)
data = tf.compat.v1.assign_add(var, tf.constant(1.0))
en_q = Q.enqueue(data)
qr = tf.train.QueueRunner(Q, enqueue_ops=[en_q])
init_op = tf.compat.v1.global_variables_initializer()
with tf.compat.v1.Session() as sess:
    sess.run(init_op)
    coord = tf.train.Coordinator()
    threads = qr.create_threads(sess, coord=coord, start=True)
    for i in range(300):
        print(sess.run(Q.dequeue()))
    coord.request_stop()
    coord.join(threads)
结果如下:

3.0
7.0
10.0
14.0
18.0
21.0
26.0
....

我对这个结果很困惑。由于
Q
是一个FIFO队列,即使出列和入列在两个不同的线程中,入列的数量仍然应该是
1,2,3,4,5,6,…
。为什么出列的数字可能是
3,7,10,14,…。
数字
1,2,4,5,…
在哪里?

随机性与
FIFOqueue
无关,而是线程执行并发的预期行为。这里肯定不止涉及两个线程

为了简化操作,让我们尝试在不使用
for
循环的情况下运行代码,添加一些
print
语句&a
sleep
interval&看看会发生什么:

import tensorflow as tf
import time

Q_size = 1000 # Q size
t = 1 # t in sec

Q = tf.compat.v1.FIFOQueue(Q_size, tf.float32)
var = tf.Variable(0.0)
data = tf.compat.v1.assign_add(var, tf.constant(1.0))
en_q = Q.enqueue(data)

qr = tf.train.QueueRunner(Q, enqueue_ops=[en_q])

init_op = tf.compat.v1.global_variables_initializer()

with tf.compat.v1.Session() as sess:
    sess.run(init_op)
    coord = tf.train.Coordinator()

    print('*** before qr.create_threads ***')
    print('Q.size()', sess.run(Q.size()))
    print('var', var.eval())

    threads = qr.create_threads(sess, coord=coord, start=True)

    print('*** after qr.create_threads ***')
    time.sleep(t) # sleep t sec in main to wait for all threads to finish running.
    print('Q.size()', sess.run(Q.size()))
    print('var', var.eval())

    coord.request_stop()
    coord.join(threads)    
输出:

*** before qr.create_threads ***
Q.size() 0
var 0.0

*** after qr.create_threads ***
Q.size() 1000
var 1001.0
*** before qr.create_threads ***
Q.size() 0
var 0.0

*** after qr.create_threads ***
Q.size() 1000
var 1001.0

*** for loop ***
var 1002.0
.size() 1000
var 1003.0
.size() 1000
var 1004.0
.size() 1000
var 1005.0
.size() 1000
var 1006.0
.size() 1000
var 1007.0
.size() 1000
var 1008.0
.size() 1000
var 1009.0
.size() 1000
var 1010.0
.size() 1000
var 1011.0
.size() 1000
在调用
qr
之前,不会发生任何事情。
FIFOQueue
Q
&
var
剧照中没有任何内容等于0。这是意料之中的

调用
qr.create_threads
&设置
start=True
后,
qr
执行以下操作:

3.0
7.0
10.0
14.0
18.0
21.0
26.0
....
  • 开始用您的
    排队操作
    填充
    Q
    ,在本例中,它是
    en\u Q
    。它将尝试打包尽可能多的
    en_q
    op,这取决于您的
    q
    大小
  • q
    中的每个
    en_q
    创建线程
  • 同时运行线程。(在这一点上,考虑到
    Q
    的大小,很明显不可能像OP所提到的那样只涉及两个线程。)
  • 引入
    sleep
    ,允许所有这些线程在显示输出之前完成执行。我们想知道
    qr
    创建的所有线程完成运行后
    Q
    的大小和
    var
    的值

    因此,正如预期的那样,
    Q
    填充了1000个
    en_Q
    ops&
    var
    添加了1001次

    现在,如果我们删除
    sleep
    间隔,就会得到如下所示的随机输出

    无睡眠的随机输出

    *** before qr.create_threads ***
    Q.size() 0
    var 0.0
    
    *** after qr.create_threads ***
    Q.size() 32
    var 35.0
    
    上面的随机输出表明,当我们在主线程中显示输出时,
    qr
    仍在填充
    Q
    ,在后台同时创建和运行线程

    现在,让我们将您的
    for
    循环放回,同时在循环中引入另一个
    sleep
    间隔:

    import tensorflow as tf
    import time
    
    Q_size = 1000 # Q size
    N =10 # range of for loop
    t = 1 # t in secs
    
    Q = tf.compat.v1.FIFOQueue(Q_size, tf.float32)
    var = tf.Variable(0.0)
    data = tf.compat.v1.assign_add(var, tf.constant(1.0))
    en_q = Q.enqueue(data)
    
    qr = tf.train.QueueRunner(Q, enqueue_ops=[en_q])
    
    init_op = tf.compat.v1.global_variables_initializer()
    
    with tf.compat.v1.Session() as sess:
        sess.run(init_op)
        coord = tf.train.Coordinator()
    
        print('*** before qr.create_threads ***')
        print('Q.size()', sess.run(Q.size()))
        print('var', var.eval())
    
        threads = qr.create_threads(sess, coord=coord, start=True)
    
        print('*** after qr.create_threads ***')
        time.sleep(t) # sleep t sec in main to wait for all threads to finish running.
        print('Q.size()', sess.run(Q.size()))
        print('var', var.eval())
    
        print('*** for loop ***')
        for i in range(N):
            sess.run(Q.dequeue())
            time.sleep(t) # sleep t sec in main to wait for all threads to finish running.
            print('var', var.eval())
            print('.size()', sess.run(Q.size()))
    
        coord.request_stop()
        coord.join(threads)    
    
    引入
    sleep
    允许后台线程在主线程中显示变量之前完成

    您可以在下面的输出中看到,
    var
    现在依次增加,而
    Q
    大小保持在1000。每个
    sess.run(Q.dequeue())
    调用现在从
    Q
    执行一个
    en_Q
    操作,将1添加到
    var

    我希望这澄清了你所观察到的随机性与
    Q
    是否是
    FIFOqueue
    无关。随机性是由线程并行的预期行为引起的

    输出:

    *** before qr.create_threads ***
    Q.size() 0
    var 0.0
    
    *** after qr.create_threads ***
    Q.size() 1000
    var 1001.0
    
    *** before qr.create_threads ***
    Q.size() 0
    var 0.0
    
    *** after qr.create_threads ***
    Q.size() 1000
    var 1001.0
    
    *** for loop ***
    var 1002.0
    .size() 1000
    var 1003.0
    .size() 1000
    var 1004.0
    .size() 1000
    var 1005.0
    .size() 1000
    var 1006.0
    .size() 1000
    var 1007.0
    .size() 1000
    var 1008.0
    .size() 1000
    var 1009.0
    .size() 1000
    var 1010.0
    .size() 1000
    var 1011.0
    .size() 1000