torch中的多线程threads学习
torch中的多线程threads学习
threads 包介绍
threads package的优势点:
程序中线程可以随时创建
Jobs被以回调函数的形式提交给线程系统,然后job由空闲下的thread执行
如果有ending callback(结束回调函数),那么当一个任务执行完毕将在主线程中执行该函数
Job的回调函数全部都是序列化的,包括一些界外变量(upvalue),这可以方便数据在线程之间的拷贝
job的回调函数返回值将传送给ending callback函数
线程之间同步化is easy
什么叫回调函数?
举个栗子,阐述下我的理解。
张无忌答应赵敏替她完成三件事情,也就是说赵敏可以调用张无忌做一些事情,然而张无忌并不知道赵敏让办的事情是啥。于是
赵敏: 张无忌,你帮我做件事情 (这是调用过程)
张无忌: 什么事情?     (这是回调过程,让赵敏完成任务指定)
赵敏:不要娶周芷若      (这个任务就是所谓的回调函数)
ok,回到正题,主线程可以调用其他线程完成一些事情,而其他线程所要完成的事情需要调用主线程指定,所以主线程就需要创建好任务以供其他线程调用,这个创建的就是回调函数。
***********************
Install
安装torch7之后,直接使用指令
- luarocks install threads 
 
分解Threads类
Threads 类
Threads可以用来创建线程队列
- local threads = require 'threads' 
 - local t = threads.Threads(4) -- 创建包含4个线程的线程池 
 
本质上,一个线程实例会使用到若干队列,即 线程安全任务队列:
- mainqueue   queue threads通过该队列创建 结束回调函数 与 主线程之间的联系
- threadqueue 主线程通过该队列创建 callback与 queue threads之间的联系
- threadspecificqueues 主线程通过该队列创建 callback 与指定线程间的联系
queue threads 在队列中维持一个infinite loop 等待可执行的job。 queue threads 可以从‘specific’模式转换到'nonspecfic'模式,所谓的specific模式是指特定的任务只能分配给指定的线程
什么是主线程?就是指当前执行函数的主程序,或者说创建线程池的线程
当有任务待执行时,线程池中的某个可用线程执行该任务并将结果通过mainqueue返回到主线程中,在接收这些结果的时候,可选的endcallback函数也将在主线程中执行
在Threads:synchronize()调用前不能保证所有的工作都被执行
每一个thread都有自己的lua_State,然而,serialization scheme能够让一些torch对象(storages,tensors and tds类型)自动的共享。
threads.Threads(N,[f1,f2,...])
该构造器中参数N指定了线程池中线程的个数,可选的参数f1,f2,...是一个函数队列,每一个线程都将执行这个函数队列。另外每个可选的函数都有一个threadid参数,这个参数取1-N之间的整数,对应每个线程,这就可以让不同的线程执行不同的行为
- threads.Threads(4, 
 - function(threadid) 
 - print("Initializing thread " .. threadid) 
 - end, 
 - function(threadid) 
 - if threadid == 2 then 
 - print('test--- test') 
 - end 
 - end 
 - ) 
 
另外 每一个线程的id还存储在全局变量__threadid 中
关于 Upvalues:
当反序列化一个回调函数时,upvalues必须是已知类型。由于threads.Threads()中函数f1,f2,...是按顺序反序列化的,因此可以使用一个单独的f1函数用来包含所有的定义量,然后再依次执行f2,f3,...
- require 'nn' 
 - local threads = require 'threads' 
 - local model = nn.Linear(5,10) 
 - threads.Threads(2,function(idx) require'nn';local myModel = model:clone() end) 
 
这样会出现问题,因为model是upvalues,但该model此时并不知道类型,因为require'nn'和赋值语句同时反序列化,可以如下修改
- require 'nn' 
 - local threads = require 'threads' 
 - local model = nn.Linear(5,10) 
 - threads.Threads(2, 
 - function(idx) require 'nn' end, 
 - function(idx) local myModel = model:clone() end) 
 
Threads:specific(boolean)
将threads system变为specific(true)或者non-specific(false)模式。在specific模式下,必须提供指定的thread index,该线程用来执行job。在non-specific mode下,将按顺序执行job
- threads = require'threads' 
 - local pool=threads.Threads(2,function(idx) print(string.format('current output is from thread: %d ', idx)) end) 
 - pool:specific(true) 
 - for j=1,4 do 
 - pool:addjob(2,function()print('running thread: '.. _threadid)end) 
 - end 
 - pool:synchronize() 
 
输出
- running thread: 2 
 - running thread: 2 
 - running thread: 2 
 - running thread: 2 
 
Threads:addjob([id],callback,[endcallback],[...])
This method is used to queue jobs to be executed by the pool of queue threads
id 是等待执行job的线程编号,要使用id的话必须指定specific模式,否则只能是non-specific模式。
callback函数将会在每个线程中执行,其参数即 ... 给定的参数
endcallback函数将会在主线程中执行,默认为 function() end
在线程执行之前,callback函数以及对应的参数都在主线程中序列化,除了以主线程中序列化可选参数的形式,主线程还可以通过upvalues的形式给线程传递数据
我们来看个例子
- threads = require'threads' 
 - -- 创建线程池,给定的函数列表实现创建线程时的初始化工作,每个线程都依次执行一遍列表中函数 
 - local pool=threads.Threads(2,function(idx) print(string.format('current output is from thread: %d ', idx)) end) 
 - a1=10 
 - a2=20 
 - local upvalue =30 -- 相对于线程池中线程而言是upvalues,如果不加local修饰,那么就不是upvalue 
 - for i=1,4 do 
 - pool:addjob( 
 - function(a,b) -- 回调函数,参数在后面列表中给出 
 - queuevalue = upvalue  
 - --以upvalues的形式传值给线程,这里upvalues是指主线程中的local变量,如果之前upvalue变量没有经过local修饰,--此时的queuevalue=nil 
 - print('current running threading ' .. __threadid) -- ————threadid是Lua_State全局量保存线程标号 
 - return a+b,queuevalue -- 回调函数的返回值,直接被结束回调函数接收 
 - end, 
 - function(inc,val) -- 结束回调函数 
 - upvalue = upvalue+inc 
 - print(val) 
 - end, 
 - a1, -- 给回调函数的参数 
 - a2  -- 给回调函数的参数 
 - ) 
 - end 
 - pool:synchronize()  -- 特别需要注意的是,此处要求所有的线程进行同步处理,即所有线程都完成任务了才开始执行下面的语句 
 - print('upvalue= ' .. upvalue) 
 - pool:terminate() 
 
输出:
- current output is from thread: 2 
 - current output is from thread: 1 
 - current running threading 1 
 - current running threading 2 
 - 30 
 - 30 
 - current running threading 1 
 - current running threading 2 
 - 60 
 - 60 
 - upvalue= 150 
 
==**这里还有一点需要注意,线程执行顺序是不定的,而序列化之后的upvalue是共享的,所以上面输出看似线程1 输出30,60线程2输出30,60,其实并不是这样的。比如我们创建3个线程的线程池,然后8个工作
- for j=1,8 do 
 - pool:addjob( 
 - function(a,b) 
 - queuevalue = upvalue 
 - print('current running threading ' .. __threadid) 
 - return a+b,queuevalue,__threadid 
 - end, 
 - function(inc,val,id) 
 - upvalue = upvalue+inc 
 - print(val .. '--' .. id) 
 - end, 
 - a1, 
 - a2) 
 - end 
 
那么不同次的执行结果可能如下:
- ### 输出1 
 - current output is from thread: 1 
 - current output is from thread: 2 
 - current output is from thread: 3 
 - current running threading 1 
 - 30--1 
 - current running threading 1 
 - current running threading 2 
 - current running threading 3 
 - 30--1 
 - current running threading 1 
 - 30--2 
 - current running threading 2 
 - current running threading 3 
 - current running threading 1 
 - 30--3 
 - 90--1 
 - 90--2 
 - 120--1 
 - 90--3 
 - upvalue= 270 
 - ### 输出2 
 - current output is from thread: 2 
 - current output is from thread: 3 
 - current output is from thread: 1 
 - current running threading 1 
 - current running threading 2 
 - current running threading 3 
 - current running threading 1 
 - 30--1 
 - current running threading 2 
 - current running threading 3 
 - current running threading 1 
 - 30--2 
 - current running threading 1 
 - 30--3 
 - 30--1 
 - 30--1 
 - 90--1 
 - 30--2 
 - 30--3 
 - upvalue= 270 
 
如果我们将 pool:synchronize()和print('upvalue= ' .. upvalue)语句交换,输出为:
- current output is from thread: 2 
 - current output is from thread: 1 
 - current running threading 2 
 - current running threading 1 
 - 30 
 - upvalue= 60         ### 这里出现60是由于一个线程已经结束了,他就应该执行到pool:synchronize()语句处,所以就会执行输出语句 
 - 30 
 - current running threading 2 
 - current running threading 1 
 - 60 
 - 60 
 
所以主线程和线程之间的数据传递可以通过callback函数中upvalue和arg形式(主线程->线程队列)或者endcallback函数接受值(线程池-> 主线程)
Threads:dojob()
This method is used to tell the main thread to execute the mext 'endcallback' in the queue.
一般而言除了异步执行的时候,该函数不会调用,因为同步的时候Threads:synchronize()函数自动保证所有的job都被执行
Threads:synchronize()####
保证线程队列中所有的callback和endcallback函数都被执行。当队列中有一个线程出现error时,此函数也将throw error
Threads:terminate()####
该函数将调用synchronize()函数,然后终止所有线程,清理线程池占用的内存
Threads:serialization(pkgname)####
Specify which serialization scheme should be used. 该函数应该在创建线程池之前就被调用。
这里的serialization package 应该返回的时一个serialization functions的列表。参考serialize specfications
Threads.acceptsjob([id])####
判断线程池中是否有空闲的线程,如果是specific mode必须指定线程id,表示该线程是否空闲;否则不需要指定id,判断的时整个线程池中是否有空闲线程
Threads.hasjob()
判断线程队列中是否仍然又job正在执行
Simple Example
简单示例
- -- 执行该代码的就是主线程 main thread 
 - local threads = require 'threads' 
 - local nthread = 4 
 - local njob = 10 
 - local msg = "hello from a satellite thread" 
 - local pool = threads.Threads(       --创建线程池 
 - nthread,                 --线程池中线程的个数 
 - function(threadid)       -- 可以是一个函数列表,用来初始化线程 
 - print('starting a new thread/state number ' .. threadid) 
 - gmsg = msg -- get it the msg upvalue and store it in thread state         -- 以upvalue形式访问主线程变量 
 - end 
 - ) 
 - local jobdone = 0 
 - for i=1,njob do 
 - pool:addjob(     -- 创建任务 
 - function()    -- 回调函数 
 - print(string.format('%s -- thread ID is %x', gmsg, __threadid)) 
 - return __threadid 
 - end, 
 - function(id)  -- 结束回调函数 
 - print(string.format("task %d finished (ran on thread ID %x)", i, id)) 
 - jobdone = jobdone + 1 
 - end 
 - ) 
 - end 
 - pool:synchronize()  -- 同步执行 
 - print(string.format('%d jobs done', jobdone)) 
 - pool:terminate()    -- 擦屁股 
 
总的来说线程的处理,首先创建线程池,可以初始化线程,然后创建任务,这些任务可以指定分配给的线程标号,也可以不指定,再然后线程通过回调函数执行任务,执行完之后将线程的值通过结束回调函数交给主线程。
torch中的多线程threads学习的更多相关文章
- (原)torch中threads的addjob函数使用方法
		
转载请注明出处: http://www.cnblogs.com/darkknightzh/p/6549452.html 参考网址: https://github.com/torch/threads#e ...
 - 【转】Java中的多线程学习大总结
		
多线程作为Java中很重要的一个知识点,在此还是有必要总结一下的. 一.线程的生命周期及五种基本状态 关于Java中线程的生命周期,首先看一下下面这张较为经典的图: 上图中基本上囊括了Java中多线程 ...
 - 多线程的学习与python实现
		
学习了进程与线程,现对自己的学习进行记录. 目录: 一.进程与线程的概念,以及联系与区别 二.多线程 三.python中多线程的应用 四.python实例 五.参考文献 一.进程与线程的概念.以及联系 ...
 - [Java123] JDBC and Multi-Threading 多线程编程学习笔记
		
项目实际需求:DB交互使用多线程实现 多线程编程基础:1.5 :( (假设总分10) 计划一个半月从头学习梳理Java多线程编程基础以及Oracle数据库交互相关的多线程实现 学习如何通过代码去验证 ...
 - 多线程多进程学习threading,queue线程安全队列,线程间数据状态读取。threading.local() threading.RLock()
		
http://www.cnblogs.com/alex3714/articles/5230609.html python的多线程是通过上下文切换实现的,只能利用一核CPU,不适合CPU密集操作型任务, ...
 - [转载]ArcGIS Engine 中的多线程使用
		
ArcGIS Engine 中的多线程使用 原文链接 http://anshien.blog.163.com/blog/static/169966308201082441114173/ 一直都想写 ...
 - Java多线程技术学习笔记(二)
		
目录: 线程间的通信示例 等待唤醒机制 等待唤醒机制的优化 线程间通信经典问题:多生产者多消费者问题 多生产多消费问题的解决 JDK1.5之后的新加锁方式 多生产多消费问题的新解决办法 sleep和w ...
 - Java多线程技术学习笔记(一)
		
目录: 概述 多线程的好处与弊端 JVM中的多线程解析 多线程的创建方式之一:继承Thread类 线程的状态 多线程创建的方式之二:实现Runnable接口 使用方式二创建多线程的好处 多线程示例 线 ...
 - (原)torch中微调某层参数
		
转载请注明出处: http://www.cnblogs.com/darkknightzh/p/6221664.html 参考网址: https://github.com/torch/nn/issues ...
 
随机推荐
- EasyUI之Layout布局和Tabs页签的使用
			
1.JQuery EasyUI之LayOut布局 EasyUI是一款基于JQuery开发的前端框架,它集成很多漂亮的样式和相应的功能,大大方便了我们对前端开发的难度.对于web项目而言,主页面的一定是 ...
 - Maven搭建Nexus私有仓库
			
下载压缩包nexus-2.13.0-01-bundle.tar.gz 解压后有两个目录 进入程序目录启动 ./nexus start 启动告警(确认用root启动把以下加入到环境变量) export ...
 - Java Naming and Directory Interface (JNDI)  Java 命名和目录接口
			
https://www.oracle.com/technetwork/java/jndi/index.html Lesson: Overview of JNDI (The Java™ Tutorial ...
 - Python开发【模块】:Urllib(一)
			
Urllib模块 1.模块说明: Urllib库是Python中的一个功能强大.用于操作的URL,并在做爬虫的时候经常要用到的库.在Python2.X中,分Urllib库和Urllib库,Python ...
 - 10.numpy基本用法
			
参考: https://blog.csdn.net/sinat_32547403/article/details/54017551
 - glassfish3新建domain
			
下载路径:http://download.oracle.com/glassfish/3.1.2.2/release/index.html .zip (解压缩)cd /glassfish3/glassf ...
 - PAT 1057 Stack [难][树状数组]
			
1057 Stack (30)(30 分) Stack is one of the most fundamental data structures, which is based on the pr ...
 - Python3.x:函数定义
			
Python3.x:函数定义 1,函数定义: def 函数名称([参数1,参数2,参数3......]): 执行语句 2,实例一(不带参数和没返回值): def helloWorld(): print ...
 - JAVA面试题整理(6)-JVM
			
JVM 1.详细jvm内存模型 2.讲讲什么情况下回出现内存溢出,内存泄漏? 3.说说Java线程栈 4.JVM 年轻代到年老代的晋升过程的判断条件是什么呢? 5.JVM 出现 fullGC 很频繁, ...
 - 20145118 《Java程序设计》  第3周学习总结
			
20145118 <Java程序设计> 第3周学习总结 教材学习内容总结 第四章开始接触到了Java的核心内容---对象这个概念,在这里为避免混淆,列举面向过程和面向对象的区别: 面向对象 ...