线程
1、线程的简单调用:
_thread:
_thread线程调用函数需要加入数组tuple()
#coding=utf-8
import thread
from time import sleep,ctimedef sing():
for i in range(3):
print "正在唱歌...%d"%i
sleep(1)
def dance():
for i in range(3):
print "正在跳舞...%d"%i
sleep(1)
if __name__ == '__main__':
print '---开始---:', ctime()
# 第一个参数:创建的新线程要执行的代码
# 第二个参数给新线程执行sing函数时传递的参数,即使没有参数也要传递空元组
thread.start_new_thread(sing, ())
thread.start_new_thread(dance, ())
sleep(5)
print '---结束---:', ctime()
threading:
#coding=utf-8
import threading
import time
def saySorry():
print "亲爱的,我错了,我能吃饭了吗?"
time.sleep(1)
if __name__ == "__main__":
for i in range(5):
#threading线程调用函数,输入函数名saySorry即可,不要加(),也不不需要加入数组格式
t = threading.Thread(target=saySorry)
t.start()
2、线程的复杂调用:
子类继承threading:
#coding=utf-8
import threading
import time
class MyThread(threading.Thread):
#如果线程接收参数,在__init__(self,*number)接收即可,*可以为任意个,包括0,number类型为tuple
def run(self):
for i in range(3):
time.sleep(1)
msg = "I'm "+self.name+' @ '+str(i)
print msg
def test():
for i in range(5):
t = MyThread()
t.start()
if __name__ == '__main__':
test()
3、线程的互斥锁(如何修改共享资源):
#创建锁
mutex = threading.Lock()
#锁定
mutex.acquire([timeout]) #[timeout]不写,默认为1,在1秒之内完成工作自动释放,0会出现难于预计的后果
#释放
mutex.release()
4、锁的总结:
当一个线程调用锁的acquire()方法获得锁时,锁就进入“locked”状态。每次只有一个线程可以获得锁。如果此时另一个线程试图获得这个锁,该线程就会变为“blocked”状态,称为“同步阻塞”
直到拥有锁的线程调用锁的release()方法释放锁之后,锁进入“unlocked”状态。线程调度程序从处于同步阻塞状态的线程中选择一个来获得锁,并使得该线程进入运行(running)状态。
锁的好处:
- 确保了某段关键代码只能由一个线程从头到尾完整地执行
锁的坏处:
- 阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了.
- 由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁
5、线程死锁:
import threading
import time
boymutex=threading.Lock()
girlmutext=threading.Lock()
class boy(threading.Thread):
def run(self):
if boymutex.acquire(1):#没有参数,一直等待acquire成功返回True
print(self.name+"boy i am sorry up")
time.sleep(1)
if girlmutext.acquire(1):
print(self.name + "boy i am sorry down")
girlmutext.release()
boymutex.release()
class girl(threading.Thread):
def run(self):
if girlmutext.acquire(1): # 没有参数,一直等待,
print(self.name + "girl i am sorry up")
time.sleep(2)
#27-到这里解锁
if boymutex.acquire(1):
print(self.name + "girl i am sorry down")
boymutex.release()
girlmutext.release()
boy1=boy()
boy1.start()
girl1=girl()
girl1.start()
6、线程Rlock:acquire是依附于threading.Lock或threading.RLock存在
import threading
import time
class MyThread(threading.Thread):
def run(self):
global num
time.sleep(1)
if mutex.acquire(1):
num = num+1
msg = self.name+' set num to '+str(num)
print (msg)
mutex.acquire() #第二次锁
mutex.release() #第二次锁的解锁
mutex.release()
num = 0
mutex = threading.RLock()
def test():
for i in range(5):
t = MyThread()
t.start()
if __name__ == '__main__':
test()
6&7、线程的condition锁(重要):
# -*- coding: utf-8 -*-
import threading, time
class Seeker(threading.Thread):
def __init__(self, cond, name):
super(Seeker, self).__init__()
self.cond = cond
self.name = name
def run(self):
self.cond.acquire()
print (self.name + ': 我已经把眼睛蒙上了')
"""
notify源码解析:
__waiters = self.__waiters
waiters = __waiters[:n] # 获取等待队列中的n个等待锁
for waiter in waiters:
waiter.release() # 释放Hider的等待锁
try:
__waiters.remove(waiter)
except ValueError:
pass
"""
# 释放n个waiter锁,waiter线程准备执行
self.cond.notify()
print('notifyed...')
# 释放condition条件锁,waiter线程Hider真正开始执行
self.cond.wait()
print('waited...')
print (self.name + ': 我找到你了 ~_~')
self.cond.notify()
self.cond.release()
print (self.name + ': 我赢了')
class Hider(threading.Thread):
def __init__(self, cond, name):
super(Hider, self).__init__()
self.cond = cond
self.name = name
def run(self):
self.cond.acquire()
"""
wait()源码解析:
waiter = _allocate_lock() # 创建一把等待锁,加入waiters队列,等待notify唤醒
waiter.acquire() # 获取锁
self.__waiters.append(waiter)
saved_state = self._release_save() # 释放condition.lock全局条件锁,以便其他等待线程执行
if timeout is None:
waiter.acquire() # 再次获取锁,因为已经锁定无法继续,等待notify执行release
"""
# wait()释放对琐的占用,同时线程挂起在这里,直到被notify并重新占有琐。
self.cond.wait()
print (self.name + ': 我已经藏好了,你快来找我吧')
self.cond.notify()
self.cond.wait()
self.cond.release()
print (self.name + ': 被你找到了,哎~~~')
cond = threading.Condition()
hider = Hider(cond, 'hider')
seeker = Seeker(cond, 'seeker')
hider.start()
seeker.start()
hider.join()
seeker.join()
print('end...')
7、threading线程共享queue:
# -*- coding:utf-8 -*-
import threading
import queue
import time
import random
myqueue=queue.Queue(10)
class butThread(threading.Thread):
def __init__(self,index,myqueue):
threading.Thread.__init__(self)
self.index=index
self.myqueue=myqueue
def run(self):
while True:
time.sleep(1)
item=self.myqueue.get()
if item is None:
break
print("客户",self.index,"物品",item,"买到")
self.myqueue.task_done()
class creatorThread(threading.Thread):
def __init__(self,index,myqueue):
threading.Thread.__init__(self)
self.index=index
self.myqueue=myqueue
def run(self):
while True:
time.sleep(3)
num=random.randint(1,1000000)
self.myqueue.put("生产者"+str(self.index)+"肉夹馍"+str(num))
print("input 生产者"+str(self.index)+"肉夹馍"+str(num))
self.myqueue.task_done()
for i in range(3): #无限循环,对象生产和获取
creatorThread(i,myqueue).start()
for i in range(8):
butThread(i,myqueue).start()
# for i in range(10): #简单生产,对象无限获取
# myqueue.put("肉夹馍"+str(i))
#
# for i in range(8):
# butThread(i,myqueue).start()
# for i in range(3): #无限循环,对象一次性生产,简单一次性获取
# creatorThread(i,myqueue).start()
# while True:
# time.sleep(10)
# print("----------")
# while not myqueue.empty():
# print(myqueue.get())
# print("-----------")
8、threading线程的evnet通讯
import threading
import time
def goevent():
e=threading.Event() #事件对象
def go(): #函数内部的函数,嵌套
for i in range(10): #i为每一个等待的资源
e.wait() #等待
e.clear()#清理
print(i)
threading.Thread(target=go).start()#创建一个线程,go
return e
ev= goevent()
for i in range(10): #等待多少秒
time.sleep(i)
ev.set()
输出:
0
1
2
3
4
5
6
7
8
9
8.1、threading线程的evnet通讯2(深入并通俗易懂)
Event对象用于线程间的相互通信,实际上Condition对象在一定程度上已经实现线程间的通信,但Condition对象是每次仅有一个线程对共享数据进行操作,其他线程则等待。而Event对象是由线程设置的信号标志,如果信号标志为真,则其他线程等待直到信号解除。
8.2、Event对象方法:
set():设置Event对象内部的信号为真,
isSet():判断内部信号标志的状态,当Event对象使用set()方法后,isSet()方法返回真
clear():清除内部信号标志,当使用clear()方法后,isSet()方法就会返回假
wait():当内部信号为真的时才会执行,如果内部信号为假则会一直等待
#-*- coding:utf-8 -*-
import threading # 导入threading模块
class mythread(threading.Thread):
def __init__(self,threadname):
threading.Thread.__init__(self,name = threadname)
def run(self):
global event # 使用全局Event对象
if event.isSet(): # 判断Event对象内部信号标志
# print(event.isSet())
event.clear() # 若已设置标志则清除,把event的值设为Flase,这样wait遇到False才会等待,如果wait遇到True永远不会停
# print(event.isSet())
event.wait() # 调用wait方法
# print(event.isSet())
print (self.getName())
else:
# print (self.getName())
event.set() # 设置Event对象内部信号标志
print (self.getName())
event = threading.Event() # 生成Event对象
event.set() # 设置Event对象内部信号标志,第一次就把event设置为True
tl = []
for i in range(10):
t = mythread(str(i))
tl.append(t) # 生成线程列表
for i in tl:
i.start() # 运行线程
运行结果:
1 #event event.set 可以分别理解为一个房间和一个房间的开关
0
3
2
5
4
7
6
9
8
9、线程:join阻塞主进程和setDaemon守护线程
import threading
import random
import time
class MyThread(threading.Thread):
def run(self):
wait_time=random.randrange(1,10)
print ("%s will wait %d seconds" % (self.name, wait_time))
time.sleep(wait_time)
print ("%s finished!" % self.name)
if __name__=="__main__":
print ('main thread is waitting for exit...')
for i in range(5):
t = MyThread()
#setDaemon(True)把子进程设为守护线程(非主要),主进程可以自由执行
t.setDaemon(True)
#join默认不设值,阻塞主进程,必须等待全部子进程执行完。
#t.join() #join(1)设置为1的话,只会等待时间较短的子进程,再执行主进程,最后执行剩余的长时间sleep的子进程
t.start()
print ('main thread finished!')
###########运行结果###########
main thread is waitting for exit...
Thread-1 will wait 4 seconds
Thread-2 will wait 3 seconds
Thread-3 will wait 5 seconds
Thread-4 will wait 5 seconds
Thread-5 will wait 6 seconds
main thread finished!
10、TreadLocal
#-*- coding:utf-8 -*-
import threading
# 创建全局ThreadLocal对象:
local_school = threading.local()
def process_student():
# 获取当前线程关联的student:
std = local_school.student
print('Hello, %s (in %s)' % (std, threading.current_thread().name))
def process_thread(name):
# 绑定ThreadLocal的student:
local_school.student = name
process_student()
#target目标函数;args需要传的值,类型是tuple;name设置线程的名字
t1 = threading.Thread(target= process_thread, args=('Alice',), name='Thread-A')
t2 = threading.Thread(target= process_thread, args=('Bob',), name='Thread-B')
t1.start()
t2.start()
t1.join()
t2.join()
##运行结果
Hello, Alice (in Thread-A)
Hello, Bob (in Thread-B)
ThreadLocal最常用的地方就是为每个线程绑定一个数据库连接,HTTP请求,用户身份信息等,这样一个线程的所有调用到的处理函数都可以非常方便地访问这些资源。
小结
一个ThreadLocal变量虽然是全局变量,但每个线程都只能读写自己线程的独立副本,互不干扰。ThreadLocal解决了参数在一个线程中各个函数之间互相传递的问题
11、线程常见的函数:
11.1、semapore:线程同时运行最大并发量
import threading
import time
sem=threading.Semaphore(3) #控制线程的数量,最大并发,没有并发等待
def gothread():
#with是acquire和release的合并
with sem: #使用并发量控制
for i in range(10):
time.sleep(0.1)
print(threading.current_thread().name,i)
for i in range(4):
threading.Thread(target=gothread).start()
11.2、timer:多少秒后线程执行任务
import time
import os
import threading
'''
#主线程卡顿,主线不能干其他活
while True:
os.system("notepad")
time.sleep(5)
'''
#定时线程
def go():
os.system("notepad")
timeth=threading.Timer(5,go)
timeth.start()#5,5秒循环,go执行,新的线程
# timeth.cancel()#结束
while True:
print("OK")
time.sleep(1)
11.3、TSL:为每个线程提供独立空间
import threading
import time
data=threading.local() #class '_thread._local,线程独立存储空间
#每一个线程独立存储,x不重合
#print(type(data))
t1=lambda x:x+1 #1+1=2
t2=lambda x:x+"1" #“1”+“1”=“11”
def printdata(func,x):#func接收t1,t2产生不同的行为
data.x=x #data是一个类,动态绑定,每一个线程的x都是独立的
print(id(data.x),threading.Thread.name)
for i in range(5):
data.x=func(data.x)
print(threading.current_thread().name,data.x)
time.sleep(0.2)
threading.Thread(target=printdata,args=(t1,1)).start()
threading.Thread(target=printdata,args=(t2,"1")).start()
##运行结果
1418634336 <property object at 0x00000000028F99A8>
Thread-1 2
36809952 <property object at 0x00000000028F99A8>
Thread-2 11
Thread-1 3
Thread-2 111
Thread-1 4
Thread-2 1111
Thread-1 5
Thread-2 11111
Thread-1 6
Thread-2 111111