对不起,我是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, ...
在哪里?
答案 0 :(得分:0)
随机性与FIFOqueue
无关,但与线程执行的并发性是预期的行为。肯定涉及的线程不止2个。
为简化起见,让我们尝试在没有for
循环的情况下运行代码,添加一些print
语句和sleep
间隔,然后看看会发生什么:
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
在调用qr
之前,什么都没有发生。 FIFOQueue
Q
和var
中的值仍然等于0。这是预期的。
调用qr.create_threads
并设置start=True
后,qr
执行以下操作:
Q
(在本例中为enqueue_ops
)填充en_q
。它将尝试打包尽可能多的en_q
操作,这取决于您的Q
大小。en_q
中的每个Q
创建线程。Q
的大小,很明显,正如OP所提到的,仅涉及2个线程。)引入sleep
是为了允许所有这些线程在我们显示输出之前完成执行。我们想知道Q
创建的所有线程完成运行后var
的大小和qr
的值是什么。
因此,正如预期的那样,Q
被填充了1000次en_q
操作,而var
被添加了1001次。
现在,如果我们删除sleep
间隔,我们将得到如下所示的随机输出。
不带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())
调用现在从{{1 }},将1加到en_q
。
我希望这可以清除您观察到的随机性与Q
是否为var
无关。随机性是由线程并行性的预期行为引起的。
输出:
Q