如何在python多线程中调用同一个session会话?

这个问题源于我在看的一个强化学习代码:

https://gitee.com/devilmaycry812839668/scalable_agent

在众多的机器学习的分支中,凡是使用深度学习模型的基本都不会考虑本文的这个问题,不论是监督学习还是非监督学习,其学习过程都可以使用串行计算的算法逻辑来解决,但是唯独强化学习是个例外。

强化学习可以使用串行方式计算,但是由于其有采样这个操作并且采样效率还比较低下,因此在强化学习的并行采样中就出现了本文的这个问题,或者更具体的是说在一个进程的多个线程中是否可以调用同一个session,这个主进程可以是C++的也可以是python的,这个session可以是TensorFlow的同样也可以是pytorch的,为了不过大扩张本文的讨论范围,本文的设定是只讨论python下多线程对TensorFlow的同一个session会话的调用情况,不过也计划在本文后再做一个C++下多进程对TensorFlow同一个session会话的调用情况研究。

---------------------------------------

先从一个外网的poster来看这个问题:

[英] Reusing Tensorflow session in multiple threads causes crash(在多个线程中重用Tensorflow会话会导致崩溃)(中文翻译版本)

上文同样是从强化学习的应用背景出发,原文作者给出了一个python多线程调用统一TensorFlow会话session的代码:

import tensorflow as tf

import threading

def thread_function(sess, i):
inn = [1.3, 4.5]
A = tf.placeholder(dtype=float, shape=(None), name="input")
P = tf.Print(A, [A])
Q = tf.add(A, P)
sess.run(Q, feed_dict={A: inn}) def main(sess): thread_list = []
for i in range(0, 4):
t = threading.Thread(target=thread_function, args=(sess, i))
thread_list.append(t)
t.start() for t in thread_list:
t.join() if __name__ == '__main__': sess = tf.Session()
main(sess)

该代码很不幸,不能运行,报错:RuntimeError: The Session graph is empty. Add operations to the graph before calling run().

根据poster中回帖给出的解决方法可以知道,在主线程中Session启动后调用的计算图graph默认就是默认Graph,但是在子线程中则需要对使用的计算图进行指定,给出修改后的可运行的代码:

import tensorflow as tf
import threading def thread_function(i):
with sess.graph.as_default():
inn = [1.3, 4.5]
A = tf.placeholder(dtype=float, shape=(None), name="input")
P = tf.Print(A, [A, "hello:"])
Q = tf.add(A, P)
# print(sess.run(Q, feed_dict={A: inn}))
sess.run(Q, feed_dict={A: inn}) def main(sess):
thread_list = []
for i in range(0, 4):
t = threading.Thread(target=thread_function, args=(i,))
thread_list.append(t)
t.start() for t in thread_list:
t.join() if __name__ == '__main__':
sess = tf.Session()
main(sess)

不过需要注意的是由于python中的GIL,因此python中线程是不能并发的,也就是说同一时刻多个线程中只能有一个线程在运行,因此即使多个python线程调用同一个session会话,其总的用时是单线程运行时间的累加,并不能起到加速的作用,为了更清晰的验证给出下面代码:

import tensorflow as tf
import numpy as np
import threading
import time def thread_function(sess, Q, A, inn):
with sess.graph.as_default():
sess.run(Q, feed_dict={A: inn}) def main(sess):
A = tf.placeholder(dtype=float, shape=(500, 500), name="input")
Q = tf.Variable(tf.random_normal(shape=(500, 500)), dtype=float, name="input_variable")
Q = tf.add(A, Q)
for _ in range(10000):
Q += tf.matmul(A, Q)
# print(sess.run(Q, feed_dict={A: inn})) inn = np.random.random(size=(500, 500))
thread_list = []
a_time = time.time() sess.run(tf.global_variables_initializer()) print(a_time)
for i in range(0, 3):
t = threading.Thread(target=thread_function, args=(sess, Q, A, inn))
thread_list.append(t)
t.start() for t in thread_list:
t.join()
b_time = time.time()
print(b_time)
print(b_time-a_time) if __name__ == '__main__':
sess = tf.Session()
main(sess)

上面代码,在python中开三个线程调用相同的TensorFlow的Session会话,结果:

改成两个线程:

改成一个线程:

可以看到虽然可以使用python多线程调用同一个TensorFlow的session会话,但是并不能对性能有什么提升,多线程运算其实也是串行的,或许只有少量提升,其主要原因就是python的多线程其实不能并发运行的。

===========================================

tensorflow1.x——如何在python多线程中调用同一个session会话的更多相关文章

  1. 如何在Python脚本中调用外部命令(就像在linux shell或Windows命令提示符下输入一样)

    如何在Python脚本中调用外部命令(就像在linux shell或Windows命令提示符下输入一样) python标准库中的subprocess可以解决这个问题. from subprocess ...

  2. python 多线程中的同步锁 Lock Rlock Semaphore Event Conditio

    摘要:在使用多线程的应用下,如何保证线程安全,以及线程之间的同步,或者访问共享变量等问题是十分棘手的问题,也是使用多线程下面临的问题,如果处理不好,会带来较严重的后果,使用python多线程中提供Lo ...

  3. 手摸手教你如何在 Python 编码中做到小细节大优化

    手摸手教你如何在 Python 编码中做到小细节大优化 在列表里计数 """ 在列表里计数,使用 Python 原生函数计数要快很多,所以尽量使用原生函数来计算. &qu ...

  4. 如何在C语言中调用Swift函数

    在Apple官方的<Using Swift with Cocoa and Objectgive-C>一书中详细地介绍了如何在Objective-C中使用Swift的类以及如何在Swift中 ...

  5. 【转载】如何在C语言中调用shell命令

    转载自:http://blog.csdn.net/chdhust/article/details/7951576 如何在C语言中调用shell命令 在linux操作系统中,很多shell命令使用起来非 ...

  6. $Django 多表操作(增删改查,基于双下划线,对象的查询) 在Python脚本中调用Django环境

    在Python脚本中调用Django环境. import osif __name__ == '__main__': os.environ.setdefault("DJANGO_SETTING ...

  7. django系列5.4--ORM中执行原生SQL语句, Python脚本中调用django环境

    ORM执行原生sql语句 在模型查询API不够用的情况下,我们还可以使用原始的SQL语句进行查询. Django 提供两种方法使用原始SQL进行查询:一种是使用raw()方法,进行原始SQL查询并返回 ...

  8. Django框架(八)--单表增删改查,在Python脚本中调用Django环境

    一.数据库连接配置 如果连接的是pycharm默认的Sqlite,不用改动,使用默认配置即可 如果连接mysql,需要在配置文件中的setting中进行配置: 将DATABASES={} 更新为 DA ...

  9. Django框架(九)—— 单表增删改查,在Python脚本中调用Django环境

    目录 单表增删改查,在Python脚本中调用Django环境 一.数据库连接配置 二.orm创建表和字段 三.单表增删改查 1.增加数据 2.删除数据 3.修改数据 4.查询数据 四.在Python脚 ...

  10. Python--day69--pythonDjango终端打印SQL语句、在Python脚本中调用Django环境

    Django终端打印SQL语句 在Django项目的settings.py文件中,在最后复制粘贴如下代码: LOGGING = { 'version': 1, 'disable_existing_lo ...

随机推荐

  1. UniRx-unirx中的对象池

    UniRx-unirx中的对象池 对象池Unirxunity 对象池 一.对象池模式 <游戏设计模式-对象池模式> 1.概念 定义一个池对象,其包含了一组可重用对象. 其中每个可重用对象都 ...

  2. 一行超长日志引发的 “血案” - Containerd 频繁 OOM 背后的真相

    案发现场:混沌初现 2024年6月10日,本应是平静的一天.但从上午 9 点开始,Sealos 公有云的运维监控告警就开始不停地响.北京可用区服务器节点突然出现大量 "not ready&q ...

  3. idea远程debug(物理机、docker、k8s)

    IDEA远程DEBUG 1:物理机部署的Springboot项目远程DEBUG 1.1:idea配置 点击"Edit Configurations",再点击+,选择Remote, ...

  4. java 编程思想--个人总结

    从应用开始思考----思考解题思路--将思路分解成一步一步的步骤-----根据每一步的步骤思考如何用代码实现-- -- 不要心急,可以一块一块来完成-- 最后再思考如何用代码实现每两块之间的连接--- ...

  5. vscode插件记录

    前言 vscode因插件而强大. 记录一下好用的插件,以备后续参考. 插件汇总 内容1-14来源于<正点原子 I.MX6U驱动开发指南>4.5节, C/C++,这个肯定是必须的; C/C+ ...

  6. 小产品,快变现,Solo社区共建者 James 专访

    采访人:徐小夕. 本次受邀采访的嘉宾是Solo社区计划负责人&Solo社区联合创建者 James Pan(老潘). 专访内容 1. Solo社区创建的背景 随着国内软件市场内卷加剧,加上大环境 ...

  7. Ubuntu下的LabVIEW开发

    1 虚拟机的安装 我用的是Virtua Box 的虚拟机,当然也有其他的类似软件:下载虚拟机的网址: https://www.virtualbox.org/wiki/Downloads 自行去下载合适 ...

  8. 【漏洞分析】Li.Fi攻击事件分析:缺乏关键参数检查的钻石协议

    背景信息 2024 年 7 月 16日,Li.Fi 协议遭受黑客攻击,漏洞成因是钻石协议中 diamond 合约新添加的 facet 合约没有对参数进行检查,导致 call 函数任意执行.且 diam ...

  9. Day 1 - 二分

    整数二分 我们可以做到每次排除一半的答案,时间复杂度 \(O(\log n)\). long long l = L, r = R; while(l <= r) { long long mid = ...

  10. 学习笔记--Java中this关键字

    Java中this关键字 关于Java语言中的this关键字 this 是一个关键字,翻译为:这个 this 是一个引用,一个变量,this变量中保存的内存地址指向自身 每一个对象都有自己的this, ...