python线程池wait_python线程、线程池

一、Python线程

Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元。

1、创建线程

1.1 自定义线程

#自定义线程

importthreadingimporttime#创建一个线程,继承threading.Thread

classMyThread(threading.Thread):def __init__(self, num):

threading.Thread.__init__(self)

self.num=num#每个线程执行的函数(任务)

defrun(self):print('running on number:%s' %self.num)

time.sleep(3)if __name__ == '__main__':for i in range(3):

t1= MyThread(i + 10)

t2= MyThread(i + 100)

t1.start()

t2.start()#----------- 输出结果---------------

running on number:10running on number:100running on number:11running on number:101running on number:12running on number:102

1.2 普通创建

importthreadingimporttime

# 全局变量

gl_num=0defshow(arg):globalgl_num

time.sleep(1)

gl_num+= 1

print(gl_num)for i in range(3):

t= threading.Thread(target=show, args=(i, ))

t.start()print('main thread stop')

上述代码创建了3个“前台”线程,然后控制器就交给了CPU,CPU根据指定算法进行调度,分片执行指令。

更多方法:

start 线程准备就绪,等待CPU调度

setName 为线程设置名称

getName 获取线程名称

setDaemon 设置为后台线程或前台线程(默认)

如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均停止

如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止

join 逐个执行每个线程,执行完毕后继续往下执行,该方法使得多线程变得无意义

run 线程被cpu调度后自动执行线程对象的run方法

2、线程锁(Lock、RLock)

由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,当多个线程同时修改同一条数据时可能会出现脏数据,所以,出现了线程锁 - 同一时刻允许一个线程执行操作。

ContractedBlock.gif

ExpandedBlockStart.gif

#!/usr/bin/env python#-*- coding:utf-8 -*-

importthreadingimporttime

gl_num=0defshow(arg):globalgl_num

time.sleep(1)

gl_num+=1

printgl_numfor i in range(10):

t= threading.Thread(target=show, args=(i,))

t.start()print 'main thread stop'

未使用锁代码

Python多线程同步Lock、RLock、Semaphore、Event实例

Lock & RLock 用来确保多线程多共享资源的访问

Semaphore用来确保一定资源多线程访问时的上限

Event是最简单的线程间通信的方式

ContractedBlock.gif

ExpandedBlockStart.gif

一、多线程同步

由于CPython的python解释器在单线程模式下执行,所以导致python的多线程在很多的时候并不能很好地发挥多核cpu的资源。大部分情况都推荐使用多进程。

python的多线程的同步与其他语言基本相同,主要包含:

Lock&RLock :用来确保多线程多共享资源的访问。

Semaphore : 用来确保一定资源多线程访问时的上限,例如资源池。

Event : 是最简单的线程间通信的方式,一个线程可以发送信号,其他的线程接收到信号后执行操作。

二、实例1)Lock &RLock

Lock对象的状态可以为locked和unlocked

使用acquire()设置为locked状态;

使用release()设置为unlocked状态。

如果当前的状态为unlocked,则acquire()会将状态改为locked然后立即返回。当状态为locked的时候,acquire()将被阻塞直到另一个线程中调用release()来将状态改为unlocked,然后acquire()才可以再次将状态置为locked。

Lock.acquire(blocking=True, timeout=-1),blocking参数表示是否阻塞当前线程等待,timeout表示阻塞时的等待时间 。如果成功地获得lock,则acquire()函数返回True,否则返回False,timeout超时时如果还没有获得lock仍然返回False。

RLock与Lock的区别是:RLock中除了状态locked和unlocked外还记录了当前lock的owner和递归层数,使得RLock可以被同一个线程多次acquire()。

lock&Rlock 理论知识

RLock 锁实例

#lock = threading.RLock()#lock = threading.Lock()#互斥锁,同一时刻只允许一个线程执行操作

importthreadingimporttime#设置一个全局变量

gl_num =0#lock = threading.Lock()#可以归执行锁操作,一般使用该锁

lock =threading.RLock()deffunc():#加锁

lock.acquire()#函数里要想修改全局变量,需要先声明

globalgl_num

gl_num+= 1time.sleep(1)print(gl_num)#释放锁

lock.release()for i in range(3):

t= threading.Thread(target=func)

t.start()print('main thread stop')

信号量(Semaphore)

Semaphore管理一个内置的计数器,每当调用acquire()时内置计数器-1;调用release() 时内置计数器+1;

计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()。

Semaphore实例:(允许同一时间有五个线程同时运行)

#信号量(semaphore)

importtime, threadingdefrun(n):#信号量,加锁

semaphore.acquire()

time.sleep(1)print('run the thread: %s' %n)#信号量,释放

semaphore.release()if __name__ == '__main__':

num=0#创建信号量,并且最多允许5个线程同时运行

semaphore = threading.BoundedSemaphore(5)for i in range(20):

t= threading.Thread(target=run, args=(i, ))

t.start()print('main thread stop')

事件(event)

python线程的事件用于主线程控制其他线程的执行,事件主要提供了三个方法 set、wait、clear。

Event内部包含了一个标志位,初始的时候为false。

可以使用使用set()来将其设置为true;

或者使用clear()将其从新设置为false;

可以使用is_set()来检查标志位的状态;

另一个最重要的函数就是wait(timeout=None),用来阻塞当前线程,直到event的内部标志位被设置为true或者timeout超时。如果内部标志位为true则wait()函数理解返回。

event 实例:(当inp为true时才会执行print('execute'))

#事件(event)

importthreadingdefdo(event):print('start')

event.wait()print('execute')#创建event对象

event_obj =threading.Event()for i in range(2):

t= threading.Thread(target=do, args=(event_obj, ))

t.start()

event_obj.clear()

inp= input('>>>>>>:')if inp == 'true':

event_obj.set()----------输出结果----------start

start>>>>>>:true

execute

execute

条件(Condition)

使得线程等待,只有满足某条件时,才释放n个线程

Condition 实例

#条件(condition)

importthreadingdefrun(n):

con.acquire()

con.wait()print('run the thread: %s' %n)

con.release()if __name__ == '__main__':

con=threading.Condition()for i in range(10):

t= threading.Thread(target=run, args=(i, ))

t.start()whileTrue:

inp= input('>>>>>>:').strip()if inp == 'q':breakcon.acquire()

con.notify(int(inp))

con.release()#--------输出结果--------

>>>>>>: 1

>>>>>>: run the thread: 02

>>>>>>: run the thread: 2run the thread:1

wait_for()

ContractedBlock.gif

ExpandedBlockStart.gif

importthreadingdefcondition_func():

ret=False

inp= input('>>>>>>')if inp == '1':

ret=Truereturnretdefrun(n):

con.acquire()

con.wait_for(condition_func)print('run the thread: %s' %n)

con.release()if __name__ == '__main__':

con=threading.Condition()for i in range(10):

t= threading.Thread(target=run, args=(i, ))

t.start()

wait_for

定时器 (Timer )

定时器,指定n秒后执行某操作

Timer 实例

#Timer定时器

from threading importTimerdefhello():print('hello, world')defhi():print('hi, world')

t= Timer(1, hello)

t1= Timer(2, hi)

t.start()

t1.start()-------输出结果---------hello, world

hi, world

线程池

1、创建线程池

# 自定义线程池

importthreadingimportqueueimporttimeclassThreadPool:def __init__(self, max_num=20):

self.queues=queue.Queue(max_num)for i inrange(max_num):

self.queues.put(threading.Thread)defget_thread(self):returnself.queues.get()defadd_thread(self):

self.queues.put(threading.Thread)

# 设定线程池 最大线程数

pool= ThreadPool(5)deffunc(arg, p):print(arg)

time.sleep(1)

pool.add_thread()for i in range(30):

thread=pool.get_thread()

t= thread(target=func, args=(i, pool))

t.start()print('main thread stop')

ContractedBlock.gif

ExpandedBlockStart.gif

importqueueimportthreadingimportcontextlibimporttime

StopEvent=object()classThreadPool(object):def __init__(self, max_num, max_task_num =None):ifmax_task_num:

self.q=queue.Queue(max_task_num)else:

self.q=queue.Queue()

self.max_num=max_num

self.cancel=False

self.terminal=False

self.generate_list= [] # self.free_list =[]def run(self, func, args, callback=None):"""线程池执行一个任务

:param func: 任务函数

:param args: 任务函数所需参数

:param callback: 任务执行失败或成功后执行的回调函数,回调函数有两个参数1、任务函数执行状态;2、任务函数返回值(默认为None,即:不执行回调函数)

:return: 如果线程池已经终止,则返回True否则None"""

ifself.cancel:return

if len(self.free_list) == 0 and len(self.generate_list)

self.generate_thread()

w=(func, args, callback,)

self.q.put(w)defgenerate_thread(self):"""创建一个线程"""t= threading.Thread(target=self.call)

t.start()defcall(self):"""循环去获取任务函数并执行任务函数"""current_thread=threading.currentThread

self.generate_list.append(current_thread)

event=self.q.get()while event !=StopEvent:

func, arguments, callback=eventtry:

result= func(*arguments)

success=TrueexceptException as e:

success=False

result=Noneif callback is notNone:try:

callback(success, result)exceptException as e:passwith self.worker_state(self.free_list, current_thread):ifself.terminal:

event=StopEventelse:

event=self.q.get()else:

self.generate_list.remove(current_thread)defclose(self):"""执行完所有的任务后,所有线程停止"""self.cancel=True

full_size=len(self.generate_list)whilefull_size:

self.q.put(StopEvent)

full_size-= 1

defterminate(self):"""无论是否还有任务,终止线程"""self.terminal=Truewhileself.generate_list:

self.q.put(StopEvent)

self.q.empty()

@contextlib.contextmanagerdefworker_state(self, state_list, worker_thread):"""用于记录线程中正在等待的线程数"""state_list.append(worker_thread)try:yield

finally:

state_list.remove(worker_thread)

pool= ThreadPool(5)defcallback(status, result):pass

defaction(i):print(i)for i in range(30):

ret=pool.run(action, (i,), callback)

time.sleep(5)print(len(pool.generate_list), len(pool.free_list))print(len(pool.generate_list), len(pool.free_list))#pool.close()#pool.terminate()

线程池

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值