Python Can';我不理解TensorOverflow train.QueueRunner的结果
对不起,我是TensorFlow的初学者。下面是TensorFlow的代码,它使用两个线程独立地排队和出列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(
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
语句&asleep
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