python期货量化书推荐_Python期货量化交易基础教程(12)12、多线程threading模块:
多线程也是实现异步任务的⽅式之⼀,通常线程是进程中的⼦任务,多个线程可以在同⼀进程中实现并发执⾏,共享进程的资源,多线程和多进程的很多操作⽅法都类似,threading模块⽀持多线程。⽬前线程被设计为不能被销毁、停⽌、暂停、恢复或中断。
threading模块的主要⽅法有:current_thread():返回当前对应调⽤者的控制线程的Thread 对象。如果调⽤者的控制线程不是利⽤threading 创建,会返回⼀个功能受限的虚拟线程对象MainThread。
enumerate(): 返回⼀个包含当前存活的线程的列表。该列表包含主线程和守护线程,current_thread() 创建的虚拟线程对象和主线程。它不包含已终结的线程和尚未开始的线程。
active_count(): 返回当前存活的线程类Thread 对象,包含主线程。返回的计数等于enumerate() 返回的列表长度。
12.1、Thread类:
线程由threading模块的Thread类创建,Thread类的参数形式为:
Thread(group: None=..., target: Optional[Callable[..., Any]]=..., name: Optional[str]=..., args: Iterable[Any]=..., kwargs:模板图片 背景
Mapping[str, Any]=..., daemon: Optional[bool]=...):group默认为None,为了⽇后扩展 ThreadGroup 类实现⽽保留的参数;target 是⽤于run()⽅法调⽤的可调⽤对象,即要执⾏的⼦线程函数,默认是 None,表⽰不需要调⽤任何⽅法;name是线程名称;args是⼦线程函数的位置参数元组,默认是空元组(,);kwargs是⼦线程函数的关键字参数字典,默认是空字典{};daemon参数为True线程为守护模式,默认为None,线程将继承当前线程的守护模式属性。
Thread类的属性和⽅法有:start():启动线程,它安排run() ⽅法在⼀个独⽴的控制进程中被调⽤,以执⾏⼦线程函数。
run():实际执⾏线程函数
is_alive():判断线程是否存活状态,存活状态返还True,否则返回False。
setName(str):设置线程名。
getName():返回线程名,也可⽤name属性获取或者修改。
java绘制图形代码
join(timeout=None):阻塞主线程,等待⼦线程执⾏结束。若给定timeout值,为超时时间,超过timeout不再阻塞。必须⽤start()启动线程才能使⽤join()⽅法。
我们看⼀下多线程的⽰例:
import time
import threading
def func(a,b,y,c=3,d=4):
print('开始执⾏⼦线程:',a,'c+d:',c+d)
t0=time.time()
global x
x=y
time.sleep(b)
print('⼦线程'+a+'的x:',x)
print('⼦线程'+a+'执⾏结束,⽤时:',time.time()-t0)
x=60
f1=threading.Thread(target=func,args=('f1',2,10),kwargs={'c':5,'d':6})
f2=threading.Thread(target=func,name='mm',args=('f2',6,100),kwargs={'c':7,'d':8})
f3=threading.Thread(target=func,name='nn',args=('f3',10,200),kwargs={'c':9,'d':10})
t0=time.time()
f1.setName('kk')
f1.start()
print('f1执⾏状态:',f1.is_alive())
f1.join()
print('f1执⾏状态:',f1.is_alive())
#f3.daemon=True
f2.start()
f3.start()
print('当前的线程变量:',threading.current_thread())
print('正在执⾏的线程列表:',umerate())
print('正在执⾏的线程数量',threading.active_count())
print('f2执⾏状态:',f2.is_alive())
f2.join(2)
print('f2执⾏状态:',f2.is_alive())
print('⼦线程f1的名字:{0},即:{1}'.format(f1.Name()))
print('⼦线程f2的名字:{0},即:{1}'.format(f2.Name()))
print('⼦线程f3的名字:{0},即:{1}'.format(f3.Name()))
print('主线程的x:',x)
print('主线程执⾏结束,⽤时:',time.time()-t0)
'''输出结果为:开始执⾏⼦线程:f1执⾏状态: Truef1 c+d: 11⼦线程f1的x: 10⼦线程f1执⾏结束,⽤时: 2.0015344619750977f1执⾏状态: False开始执⾏⼦线程: 开始执⾏⼦线程:f2 当前的线程变量:c+d:f3 <_mainthread started>15c+d:正在执⾏的线程列
表:19[<_mainthread started>, , ]正在执⾏的线程数量 3f2执⾏状态: Truef2执⾏状态: True⼦线程f1的名字:kk,即:kk⼦线程f2的名
字:mm,即:mm⼦线程f3的名字:nn,即:nn主线程的x: 200主线程执⾏结束,⽤时: 4.018061876296997⼦线程f2的x: 200⼦线程f2执⾏结束,⽤时: 6.00093674659729⼦线程f3的x: 200⼦线程f3执⾏结束,⽤时: 10.00103235244751'''
该例实例化了三个⼦线程f1、f2、f3,当前程序为主线程,主线程和三个⼦线程并发执⾏,因此最终执⾏的时间和最慢的⼦线程f3的时间⼀样,从输出结果可以知道⼦线程⾥调⽤线程⽅法的执⾏过程。
需要注意的是:主线程⾥定义的全局变量x被⼦线程修改了,正说明⼦线程共⽤了主线程的资源,因此,多线程更容易出现资源竞争的可能。
也可以通过继承Thread类⾃定义线程类以实现个性化功能,⾃定义类需要在初始化函数⾥⽤super()._
python基础教程视频免费_init__()先执⾏Thread类的初始化,并重写run()⽅法,我们把上例改写,⽤⾃定义线程类创建⼦线程,例如:
import time
import threading工作在osi七层模型
def func(a,b,y,c=3,d=4):
print('开始执⾏⼦线程:',a,'c+d:',c+d)
t0=time.time()
global x
x=y
time.sleep(b)
print('⼦线程'+a+'的x:',x)
print('⼦线程'+a+'执⾏结束,⽤时:',time.time()-t0)
return c+d
class MyThread(threading.Thread):
tcpip协议包含哪五层
def __init__(self,target,args,kwargs):
super().__init__()
self.target=target
self.args=args
self.kwargs=kwargs
def run(self):
x=60
f1=MyThread(target=func,args=('f1',2,10),kwargs={'c':5,'d':6})
f2=MyThread(target=func,args=('f2',6,100),kwargs={'c':7,'d':8})
f3=MyThread(target=func,args=('f3',10,200),kwargs={'c':9,'d':10}) t0=time.time()
f1.setName('kk')
delete删除语句怎么写f1.start()
print('f1执⾏状态:',f1.is_alive())
f1.join()
print('f1执⾏状态:',f1.is_alive())
#f3.daemon=True
f2.start()
f3.start()
print('当前的线程变量:',threading.current_thread())
print('正在执⾏的线程列表:',umerate())
print('正在执⾏的线程数量',threading.active_count())
print('f2执⾏状态:',f2.is_alive())
f2.join(2)
print('f2执⾏状态:',f2.is_alive())
print('⼦线程f1的名字:{0},即:{1}'.format(f1.Name()))
print('⼦线程f2的名字:{0},即:{1}'.format(f2.Name()))
print('⼦线程f3的名字:{0},即:{1}'.format(f3.Name()))
f2.join()
f3.join()
print('主线程的x:',x)
print('主线程执⾏结束,⽤时:',time.time()-t0)
s)
'''输出结果为:开始执⾏⼦线程:f1执⾏状态: Truef1c+d: 11⼦线程f1的x: 10⼦线程f1执⾏结束,⽤时: 2.0006656646728516f1执⾏状态: False开始执⾏⼦线程: f2开始执⾏⼦线程: c+d: 15当前的线程变量: f3<_mainthread started>c+d:正在执⾏的线程列表:
19[<_mainthread started>, , ]正在执⾏的线程数量 3f2执⾏状态: Truef2执⾏状态: True⼦线程f1的名字:kk,即:kk⼦线程f2的名
字:Thread-2,即:Thread-2⼦线程f3的名字:Thread-3,即:Thread-3⼦线程f2的x: 200⼦线程f2执⾏结束,⽤时: 6.0021514892578125⼦线程f3的x: 200⼦线程f3执⾏结束,⽤时: 10.000638961791992主线程的x: 200主线程执⾏结束,⽤时:
12.02424383163452111 15 19'''
⽤⾃定义类MyThread创建⼦线程和⽤Thread类基本没区别,⽅法的调⽤也⼀样,毕竟⽅法都是从Thread继承的,我们给函数func增加了⼀个返回值,并在run()⽅法⾥把返回值赋值给变量s,变量以self.开头,其就成了类中的全局变量,⼦线程调⽤start()⽅法启动线程时会⾃动调⽤run()⽅法,⽽
run()⽅法⼜创建了变量s,因此其可被⼦线程实例访问。
因为⼦线程共⽤了进程(主线程)的资源,⼦线程创建的类内全局变量也便写⼊了主线程的内存空间,⼦线程可在主线程中继续访问其创建的变量。
要想获取func的返回值,需要等其执⾏结束,因此要调⽤join()⽅法阻塞主线程,否则在主线程⾥执⾏类属性访问会访问不到。
类似于多进程,⼦线程若直接调⽤run()⽅法,多线程会变成同步执⾏,不再是多线程的异步执⾏了。
多线程共⽤了主线程的资源,⽐多进程更容易出现资源竞争的可能,为了解决资源竞争问题,Python也提供了多种处理⽅式。
12.2、Lock类:
Lock(互斥锁),和多进程中的锁概念类似,acquire()⽅法请求锁定,release()⽅法释放锁,因此,处在acquire()和release()之间的代码会被锁定,其他线程不能访问代码中正在处理的数据。
我们看下⽰例:
import time
import threading
def func(a,b,lock,y,c=3,d=4):
print('开始执⾏⼦线程:',a,'c+d:',c+d)
t0=time.time()
global x
lock.acquire()
time.sleep(b)
x+=y
print('⼦线程'+a+'的x:',x)
print('⼦线程'+a+'执⾏结束,⽤时:',time.time()-t0)
x='初值M'
lock=threading.Lock()
f1=threading.Thread(target=func,args=('f1',1,lock,'+被f1修改'),kwargs={'c':5,'d':6})
f2=threading.Thread(target=func,args=('f2',1,lock,'+被f2修改'),kwargs={'c':7,'d':8})
f3=threading.Thread(target=func,args=('f3',1,lock,'+被f3修改'),kwargs={'c':7,'d':8})
t0=time.time()
f1.start()
f2.start()
f3.start()
while time.time()-t0<5:
print('主线程中访问的x值:',x)
time.sleep(1)
print('主线程执⾏结束,⽤时:',time.time()-t0)
'''输出结果为:开始执⾏⼦线程:开始执⾏⼦线程: 开始执⾏⼦线程:f2主线程中访问的x值: f1f3c+d:初值Mc+d:c+d:151115⼦线程f2的x:主线程中访问的x值: 初值M+被f2修改初值M+被f2修改⼦线程f2执⾏结束,⽤时: 1.0000569820404053主线程中访问的x值: 初值M+被f2修改⼦线程f1的x: 初值M+被f2修改+被f1修改⼦线程f1执⾏结束,⽤时: 2.0011143684387207主线程中访问的x值: 初值M+被f2修改+被f1修改⼦线程f3的x: 初值M+被f2修改+被f1修改+被f3修改⼦线程f3执⾏结束,⽤时: 3.002171516418457主线程中访问的x值:初值M+被f2修改+被f1修改+被f3修改主线程执⾏结束,⽤时: 5.001286268234253'''
三个⼦线程f1、f2、f3都对主线程中的变量x修改,如果不锁定,三个⼦线程竞争修改x,由于代码少执⾏的⾮常快,主线程中输出x的值就会是最后⼀个修改值,加锁之后,⼦线程就会⼀个⼀个的修改x,从输出结果可知,主线程依次打印被修改后的值,从执⾏时间也可以看出,原本⼦线程中只⽤sleep(1)暂停1秒,但执⾏时间相继增加了1秒,说明后续线程需要等前⾯的线程释放锁后才能对x修改。
⼀个lock.acquire()对应⼀个lease(),如果存在嵌套,就会出现⼀个lock.acquire()后⾯⼜⼀个lock.acquire()的情况⽽形成死锁,因此Python⼜提供了递归锁。
12.3、Rlock类:
Rlock(递归锁)类似字典的原理,将acquire()和release()组对,不会与其他的锁产⽣混乱,因此可⽤在锁的嵌套中,例如:
import time
import threading
def func1(a,b,lock,y,c=3,d=4):
print('开始执⾏⼦线程:',a+'1','c+d:',c+d)
t0=time.time()
global x
lock.acquire()
time.sleep(b)
x+=y
print('⼦线程'+a+'1'+'的x:',x)
print('⼦线程'+a+'1'+'执⾏结束,⽤时:',time.time()-t0)

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。