TensorFlow中队列与线程

1. FIFOQueue : 先入先出的队列

import tensorflow as tf

# 在使用循环神经网络时,希望读入的训练样本是有序的可使用FIFOQueue
# 先创建一个先入先出的队列,初始化队列插入0.1,0.2,0.3三个数字
q = tf.FIFOQueue(3,tf.float32)
init = q.enqueue_many(([0.1,0.2,0.3],))    # 此时数据填充并没有完成,而是做出了一个预备工作,真正的工作要在会话中完成。
# 定义出队,+1,入队操作
x = q.dequeue()
y = x+1
q_add = q.enqueue(y)

with tf.Session() as sess:
    sess.run(init)
    quelen = sess.run(q.size())
    for i in range(quelen):
        sess.run(q_add)   # 执行两次操作,队列中的值变为0.3,1.1,1.2

    for j in range(quelen):
        print(sess.run(q.dequeue()))      # 输出队列的值

可以发现,队列的操作是在主线程的对话中依次完成。

2. RandomShuffleQueue:随机队列

# 随机队列,在出队列时以随机的顺序弹出元素
# 例如,我们在训练一些图像样本时,使用CNN的网络结构,希望可以无序的读入训练样本
q = tf.RandomShuffleQueue(capacity=10, min_after_dequeue=2, dtypes=tf.float32)
# capacity:队列最大长度,  min_after_dequeue:出队后最小长度
# 官网推荐:capacity > min_after_dequeue + (num_threads + a smaller safety margin) * batch_size
with tf.Session() as sess :
    for i in range(0,10):    # 10次入队
        sess.run(q.enqueue(i))

    for i in range(0,8):     # 8次出队
        print(sess.run(q.dequeue()))

# 在队列长度等于最小值时,执行出队操作,会发生阻断
# 在队列长度等于最大值时,执行入队操作,会发生阻断

# 解除阻断的一种方法---设置等待时间
# run_options = tf.RunOptions(time_out_in_ms = 100000) # 等待十秒
# try:
#     sess.run(q.dequeue(),options=run_options)
# except tf.errors.DeadlineExceededError:
#     print('out of range')

3. 队列管理器

Tensorflow提供了QueueRunner函数用以解决异步操作问题。其可创建一系列的线程同时进入主线程内进行操作,数据的读取与操作是同步,即主线程在进行训练模型的工作的同时将数据从硬盘读入

q = tf.FIFOQueue(1000, tf.float32)
counter = tf.Variable(0.0)  # 计数器
add_op = tf.assign_add(counter, tf.constant(1.0))  # 操作给计数器加一
enquenceData_op = q.enqueue(counter)  # 操作: 让计数器加入队列

# 创建一个队列管理器QueueRunner,用这两个操作向队列q中添加元素,目前我们只使用一个线程
qr = tf.train.QueueRunner(q, enqueue_ops=[add_op, enquenceData_op] * 1)

# 启动一个会话,从队列管理器qr中创建线程
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    enquence_threads = qr.create_threads(sess, start=True)  # 启用入队线程
    # 主线程
    for i in range(10):
        print(sess.run(q.dequeue()))

WTF???报错了???读者可以自行思考一会再看下文解释!!!

正如TensorFlow中的其他组件一样,队列就是TensorFlow图中一种有状态的节点,像变量一样,其他节点可以修改其内容。在TensorFlow中,队列不仅仅是一种数据结构,更是“异步张量取值”的一个重要机制。比如多个线程可以同时向一个队列中写元素,或者同时读取一个队列中的元素。TensorFlow提供了两个类来帮助多线程的实现:tf.Coordinator与tf.QueueRunner。从设计上这两个类必须被一起使用

看到这里,你应该知道报错的原因了!但为什么呢?QueueRunner创建的线程没有得到很好的协调,所以必须与Coordinator一起使用。

4. 线程协调器

Coordinator类用来帮助多个线程协同工作,多个线程同步终止。 其主要方法有:
    should_stop():如果线程应该停止则返回True。
    request_stop(<exception>):请求该线程停止。
    join(<list of threads>):等待被指定的线程终止。
大概过程:首先创建一个 Coordinator 对象,然后建立一些使用Coordinator对象的线程。这些线程通常一直循环运行,一直到should_stop()返回True时停止。 任何线程都可以决定计算什么时候应该停止,只需要调用request_stop()即可,同时其他线程的should_stop()将会返回True,最终停止。

import tensorflow as tf

q = tf.FIFOQueue(1000, tf.float32)
counter = tf.Variable(0.0)  # 计数器
add_op = tf.assign_add(counter, tf.constant(1.0))  # 操作给计数器加一
enquenceData_op = q.enqueue(counter)  # 操作: 让计数器加入队列

# 第一种情况,在关闭其他线程之后(除主线程之外的其它线程),调用出队操作
print('第一种情况,在关闭其他线程之后(除主线程之外的其它线程),调用出队操作')
# 创建一个队列管理器QueueRunner,用这两个操作向队列q中添加元素,目前我们只使用一个线程
qr = tf.train.QueueRunner(q, enqueue_ops=[add_op, enquenceData_op] * 1)


# 主线程
sess = tf.Session()
sess.run(tf.global_variables_initializer())

# Coordinator: 协调器, 协调线程间的关系,可以视为一种信号量,用来做同步
coord = tf.train.Coordinator()

# 启动入队线程,协调器是线程的参数
enqueue_threads = qr.create_threads(sess,coord=coord,start=True)

# 主线程
for i in range(0,10):
    print(sess.run(q.dequeue()))

coord.request_stop() # 通知其他线程关闭
coord.join(enqueue_threads) # join 操作等待其他线程结束,其他所有线程关闭之后,这一函数才能返回


# 第二种情况: 在队列线程关闭之后,调用出队操作
print('第二种情况: 在队列线程关闭之后,调用出队操作-->处理tf.errors.OutOfRange错误')
# q启动入队线程
enqueueData_threads = qr.create_threads(sess,coord=coord,start=True)

coord.request_stop()           # 通知其他线程关闭

# 主线程
for j in range(0,10):
    try:
        print(sess.run(q.dequeue()))
    except tf.errors.OutOfRangeError:
        break

coord.join(enqueueData_threads)     # join 操作等待其他线程结束,其他所有线程关闭之后,这一函数才能返回

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值