Python多线程多函数 python 多线程 函数
python多线程怎样执行函数
将你需要多线程并发执行的函数放入list中
龙凤ssl适用于网站、小程序/APP、API接口等需要进行数据传输应用场景,ssl证书未来市场广阔!成为创新互联建站的ssl证书销售渠道,可以享受市场价格4-6折优惠!如果有意向欢迎电话联系或者加微信:18980820575(备注:SSL证书合作)期待与您的合作!
import threading
threads = []
t1 = threading.Thread(target=函数名,args=参数)
threads.append(t1)
启动多线程
if __name__ == '__main__':
for t in threads:
t.setDaemon(True)
t.start()
t.join()
更多详细操作help(threading)
#coding=utf-8
import threading
from time import ctime,sleep
# 要启动的函数
def music(func):
for i in range(2):
print "I was listening to %s. %s" %(func,ctime())
sleep(1)
# 要启动的函数
def move(func):
for i in range(2):
print "I was at the %s! %s" %(func,ctime())
sleep(5)
threads = []
t1 = threading.Thread(target=music,args=(u'爱情买卖',))
threads.append(t1)
t2 = threading.Thread(target=move,args=(u'阿凡达',))
threads.append(t2)
# 函数加入线程列表
if __name__ == '__main__':
for t in threads:
t.setDaemon(True)
t.start()
t.join() #子线程完成运行之前,这个子线程的父线程将一直被阻塞,不会退出
print "all over %s" %ctime()
python之多线程原理
并发:逻辑上具备同时处理多个任务的能力。
并行:物理上在同一时刻执行多个并发任务。
举例:开个QQ,开了一个进程,开了微信,开了一个进程。在QQ这个进程里面,传输文字开一个线程、传输语音开了一个线程、弹出对话框又开了一个线程。
总结:开一个软件,相当于开了一个进程。在这个软件运行的过程里,多个工作同时运转,完成了QQ的运行,那么这个多个工作分别有多个线程。
线程和进程之间的区别:
进程在python中的使用,对模块threading进行操作,调用的这个三方库。可以通过 help(threading) 了解其中的方法、变量使用情况。也可以使用 dir(threading) 查看目录结构。
current_thread_num = threading.active_count() # 返回正在运行的线程数量
run_thread_len = len(threading.enumerate()) # 返回正在运行的线程数量
run_thread_list = threading.enumerate() # 返回当前运行线程的列表
t1=threading.Thread(target=dance) #创建两个子线程,参数传递为函数名
t1.setDaemon(True) # 设置守护进程,守护进程:主线程结束时自动退出子线程。
t1.start() # 启动子线程
t1.join() # 等待进程结束 exit()`# 主线程退出,t1子线程设置了守护进程,会自动退出。其他子线程会继续执行。
多线程和队列
1、python提供两种方式使用多线程:一个是基于函数:_thread模块或者threading模块。一个是基于类:theading.Thread
使用多线程函数包装线程对象:_thread
_thead.start_new_thead(func,*args,**kwargs)
args,**kwargs是被包装函数的入参,必须传入元祖或字典
使用多线程函数包装线程对象:threading
threading._start_new_thread(func,*args,**kwargs):开启线程,带元祖或字典
threading.currentThread():返回当前线程变量
threading.enumerate():正在运行的线程列表,不含未启动和已结束线程
threading.activeCount():返回正在运行的线程数量
threading.settrace(func):为所有threading模块启动的线程设置追踪函数,在调用run方法之前,func会被传给追踪函数
threading.setprofile(func):为所有threading模块启动的线程设置性能测试函数,也是在run方法调用前就传递给性能测试函数
使用多线程类包装线程对象:threading.Thread
Thread类提供以下方法:
run():表示线程活动的方法,线程需要控制些什么活动都在这里面定义。当线程对象一但被创建,其活动一定会因调用线程的 start() 方法开始。这会在独立的控制线程调用 run() 方法。
start():开启线程活动
join():等待线程中止,阻塞当前线程直到被调用join方法的线程中止。线程A调用线程B的join方法,那线程A将会被阻塞至线程B中止。
isAlive():返回线程是否还活动
getName():获取线程名字
setName():设置线程名字
Lock对象:实例化线程锁,包含acquire方法获取锁 和 release 方法释放锁,在最开始创建锁的时候,锁为未锁定状态,调用acquire方法后锁置为锁定状态,此时其他线程再调用acquire方法就将会被阻塞至其他线程调用release方法释放锁,如果释放一个并未被锁定的锁将会抛出异常。支持上下文管理协议,直接with lock 无需调用锁定,释放方法
Rlock对象:重入锁,相比lock增加了线程和递归的概念。比如:线程目标函数F,在获得锁之后执行函数G,但函数G也需要先获得锁,此时同一线程,F获得锁,G等待,F等待G执行,就造成了死锁,此时使用rlock可避免。一旦线程获得了重入锁,同一个线程再次获取它将不阻塞;但线程必须在每次获取它时释放一次。
daemon属性:设置该线程是否是守护线程,默认为none,需要在调用start方法之前设置好
事件对象:一个线程发出事件信号 ,其他线程收到信号后作出对应活动。实例化事件对象后,初始事件标志为flase。调用其wait方法将阻塞当前所属线程,至事件标志为true时。调用set方法可将事件标志置为true,被阻塞的线程将被执行。调用clear方法可将事件标志置为flase
注意点:
1、继承threading.Thread类,初始化时要记得继承父类的__init__方法
2、run()方法只能有一个入参,故尽量把启动线程时的参数入参到初始化的时候
3、锁要设定全局的,一个子线程获得一个锁没有意义
以下实例:有一个列表,线程A从尾到头遍历元素,线程B从头到尾将元素值重置为1,设置线程锁之前线程A遍历到头部的数据已经被修改,设置线程锁之后不会再有数据不一致的情况
import threading,time
class tt(threading.Thread):
def __init__(self,name,func,ll):
threading.Thread.__init__(self) #继承父级的初始化方法
self.name=name
self.func=func #run方法只能带一个入参,故把方法入参到初始化的时候
self.ll=ll
def run(self):
print(self.name)
threadlock.acquire() #获得锁
self.func(self.ll)
threadlock.release() #释放锁
def readd(x):
a=len(x)
while a0:
print(x[a-1])
a-=1
def sett(x):
for i in range(len(x)):
x[i]=1
print(x)
if __name__=="__main__":
l = [0,0,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
threadlock=threading.Lock() #实例化全局锁
th1=tt("read",readd,l)
th2=tt("set",sett,l)
th1.start()
th2.start()
th_list=[]
th_list.append(th1)
th_list.append(th2)
for li in th_list:
li.join() #主线程被阻塞,直到两个子线程处理结束
print("主线程结束")
2、队列
queue模块包含queue.Queue(maxsize=0)先入先出队列,queue.LifoQueue()先入后出队列,和queue.PriorityQueue()优先级可设置的队列
Queue 模块中的常用方法:
Queue.qsize() 返回队列的大小,获取的数据不可靠,因为一直有线程在操作队列,数据一直变化
Queue.empty() 如果队列为空,返回True,反之False
Queue.full() 如果队列满了,返回True,反之False
Queue.full 与 maxsize 大小对应
Queue.put(block=true,timeout=none) 将item数据写入队列,block=True,设置线程是否阻塞,设置阻塞当队列数据满了之后就会阻塞,一直到队列数据不满时继续添加,如果设置不阻塞,当队列满了就会一直到timeout到后报错
Queue.get([block[, timeout]]) 取出队列数据,block=True,设置线程是否阻塞。设置阻塞,将会等待直到队列不为空有数据可取出,设置不阻塞直到超过timeout等待时间后报错
Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号
Queue.join() 实际上意味着等到队列为空,再执行别的操作。会在队列有未完成时阻塞,等待队列无未完成的任务,取出数据get()之后还需要配置task_done使用才能让等待队列数-1
import queue,time
import threading
q=queue.Queue(maxsize=5)
def sett():
a=0
while a20:
q.put(a,True)
print("%d被put"%a)
a+=1
def gett():
time.sleep(1)
while not q.empty(): #只要队列没空,一直取数据
print("%d被取出"%q.get(True))
q.task_done() #取出一次数据,将未完成任务-1,不然使用join方法线程会一直阻塞
if __name__=="__main__":
th1=threading._start_new_thread(sett,()) #不带参数也要传入空元祖不然会报错
th2=threading._start_new_thread(gett,())
time.sleep(1) #延时主线程1S,等待put线程已经put部分数据到队列
q.join()#阻塞主线程,直到未完成任务为0
Python多线程总结
在实际处理数据时,因系统内存有限,我们不可能一次把所有数据都导出进行操作,所以需要批量导出依次操作。为了加快运行,我们会采用多线程的方法进行数据处理, 以下为我总结的多线程批量处理数据的模板:
主要分为三大部分:
共分4部分对多线程的内容进行总结。
先为大家介绍线程的相关概念:
在飞车程序中,如果没有多线程,我们就不能一边听歌一边玩飞车,听歌与玩 游戏 不能并行;在使用多线程后,我们就可以在玩 游戏 的同时听背景音乐。在这个例子中启动飞车程序就是一个进程,玩 游戏 和听音乐是两个线程。
Python 提供了 threading 模块来实现多线程:
因为新建线程系统需要分配资源、终止线程系统需要回收资源,所以如果可以重用线程,则可以减去新建/终止的开销以提升性能。同时,使用线程池的语法比自己新建线程执行线程更加简洁。
Python 为我们提供了 ThreadPoolExecutor 来实现线程池,此线程池默认子线程守护。它的适应场景为突发性大量请求或需要大量线程完成任务,但实际任务处理时间较短。
其中 max_workers 为线程池中的线程个数,常用的遍历方法有 map 和 submit+as_completed 。根据业务场景的不同,若我们需要输出结果按遍历顺序返回,我们就用 map 方法,若想谁先完成就返回谁,我们就用 submit+as_complete 方法。
我们把一个时间段内只允许一个线程使用的资源称为临界资源,对临界资源的访问,必须互斥的进行。互斥,也称间接制约关系。线程互斥指当一个线程访问某临界资源时,另一个想要访问该临界资源的线程必须等待。当前访问临界资源的线程访问结束,释放该资源之后,另一个线程才能去访问临界资源。锁的功能就是实现线程互斥。
我把线程互斥比作厕所包间上大号的过程,因为包间里只有一个坑,所以只允许一个人进行大号。当第一个人要上厕所时,会将门上上锁,这时如果第二个人也想大号,那就必须等第一个人上完,将锁解开后才能进行,在这期间第二个人就只能在门外等着。这个过程与代码中使用锁的原理如出一辙,这里的坑就是临界资源。 Python 的 threading 模块引入了锁。 threading 模块提供了 Lock 类,它有如下方法加锁和释放锁:
我们会发现这个程序只会打印“第一道锁”,而且程序既没有终止,也没有继续运行。这是因为 Lock 锁在同一线程内第一次加锁之后还没有释放时,就进行了第二次 acquire 请求,导致无法执行 release ,所以锁永远无法释放,这就是死锁。如果我们使用 RLock 就能正常运行,不会发生死锁的状态。
在主线程中定义 Lock 锁,然后上锁,再创建一个子 线程t 运行 main 函数释放锁,结果正常输出,说明主线程上的锁,可由子线程解锁。
如果把上面的锁改为 RLock 则报错。在实际中设计程序时,我们会将每个功能分别封装成一个函数,每个函数中都可能会有临界区域,所以就需要用到 RLock 。
一句话总结就是 Lock 不能套娃, RLock 可以套娃; Lock 可以由其他线程中的锁进行操作, RLock 只能由本线程进行操作。
网站题目:Python多线程多函数 python 多线程 函数
网页链接:http://ybzwz.com/article/hhjoep.html