tensorflow1.x——如何在python多线程中调用同一个session会话
如何在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会话的更多相关文章
- 如何在Python脚本中调用外部命令(就像在linux shell或Windows命令提示符下输入一样)
如何在Python脚本中调用外部命令(就像在linux shell或Windows命令提示符下输入一样) python标准库中的subprocess可以解决这个问题. from subprocess ...
- python 多线程中的同步锁 Lock Rlock Semaphore Event Conditio
摘要:在使用多线程的应用下,如何保证线程安全,以及线程之间的同步,或者访问共享变量等问题是十分棘手的问题,也是使用多线程下面临的问题,如果处理不好,会带来较严重的后果,使用python多线程中提供Lo ...
- 手摸手教你如何在 Python 编码中做到小细节大优化
手摸手教你如何在 Python 编码中做到小细节大优化 在列表里计数 """ 在列表里计数,使用 Python 原生函数计数要快很多,所以尽量使用原生函数来计算. &qu ...
- 如何在C语言中调用Swift函数
在Apple官方的<Using Swift with Cocoa and Objectgive-C>一书中详细地介绍了如何在Objective-C中使用Swift的类以及如何在Swift中 ...
- 【转载】如何在C语言中调用shell命令
转载自:http://blog.csdn.net/chdhust/article/details/7951576 如何在C语言中调用shell命令 在linux操作系统中,很多shell命令使用起来非 ...
- $Django 多表操作(增删改查,基于双下划线,对象的查询) 在Python脚本中调用Django环境
在Python脚本中调用Django环境. import osif __name__ == '__main__': os.environ.setdefault("DJANGO_SETTING ...
- django系列5.4--ORM中执行原生SQL语句, Python脚本中调用django环境
ORM执行原生sql语句 在模型查询API不够用的情况下,我们还可以使用原始的SQL语句进行查询. Django 提供两种方法使用原始SQL进行查询:一种是使用raw()方法,进行原始SQL查询并返回 ...
- Django框架(八)--单表增删改查,在Python脚本中调用Django环境
一.数据库连接配置 如果连接的是pycharm默认的Sqlite,不用改动,使用默认配置即可 如果连接mysql,需要在配置文件中的setting中进行配置: 将DATABASES={} 更新为 DA ...
- Django框架(九)—— 单表增删改查,在Python脚本中调用Django环境
目录 单表增删改查,在Python脚本中调用Django环境 一.数据库连接配置 二.orm创建表和字段 三.单表增删改查 1.增加数据 2.删除数据 3.修改数据 4.查询数据 四.在Python脚 ...
- Python--day69--pythonDjango终端打印SQL语句、在Python脚本中调用Django环境
Django终端打印SQL语句 在Django项目的settings.py文件中,在最后复制粘贴如下代码: LOGGING = { 'version': 1, 'disable_existing_lo ...
随机推荐
- PowerBI_一分钟了解POWERBI计算组功能及作用(第一部分)
1: X-mind&计算组(CALCULATION GROUP)介绍 1.1 什么是计算组 PowerBI的计算组功能可以显著减少必须创建的冗余度量值数,通过允许将DAX表达式定义为应用于模型 ...
- NumPy 差分、最小公倍数、最大公约数、三角函数详解
NumPy 差分 离散差分意味着相邻元素之间的减法. 例如,对于 [1, 2, 3, 4],离散差分将是 [2-1, 3-2, 4-3] = [1, 1, 1] 要找到离散差分,使用 diff() 函 ...
- 反模式 DI anti-patterns
反模式 DI anti-patterns 反模式DI anti-patterns <Dependency Injecttion Prinsciples,Practices, and Patter ...
- Jenkins从github拉取项目,github有更新,自动进行构建,实现自动集成
使用git之前的准备工作 1. 搭建Jenkins的机器上,有安装git,配置git的安装地址,Jenkins配置Git的安装地址 2. Global Tool Configuration - > ...
- Kubernetes 审计(Auditing)
目录 一.系统环境 二.前言 三.Kubernetes 审计简介 四.审计策略简介 五.启用审计 5.1 引入审计 5.2 启用审计 六.审计策略 6.1 记录审计阶段为:ResponseStarte ...
- 基于Python和TensorFlow实现BERT模型应用
本文分享自华为云社区<使用Python实现深度学习模型:BERT模型教程>,作者: Echo_Wish. BERT(Bidirectional Encoder Representation ...
- Kubernetes(三)实战入门
实战入门 本章介绍如何在kubernetes集群中部署一个nginx服务,并能够对其进行访问. 1. Namespace Namespace主要作用是实现多套环境的资源隔离或者多租户的资源隔离. 默认 ...
- Nuxt3 的生命周期和钩子函数(四)
title: Nuxt3 的生命周期和钩子函数(四) date: 2024/6/28 updated: 2024/6/28 author: cmdragon excerpt: 概述了Nuxt3的六个关 ...
- 浅谈k8s中cni0和docker0的关系和区别
最近在复习k8s网络方面的知识,查看之前学习时整理的笔记和文档还有过往自己总结的博客之后发现一个问题,就是在有关flannel和calico这两个k8s网络插件的文章和博客中,会涉及到cni0和doc ...
- P5327 题解
考虑把贡献摊到每个点上计算,每个点带来的贡献实际上是经过它的路径并大小,算完求和之后在除以 \(2\) 就得到了答案. 考虑怎么计算路径并大小. 考虑这样一个办法,将所有路径的起始点和终点按照 DFS ...