什么是线程
开启线程的两种方式
和开启进程的两种方式相似,只不过改一下导入的模块
进程与线程之间的区别:
- 开进程的开销远大于开线程
- 同一进程内多个线程共享该进程的内存空间
- Pid相同
Tread 方法
from threading import Thread,currentThread,active_count,enumerate
import time
def task():
print('%s is running'% currentThread().getName())
time.sleep(1)
print('%s is done'% currentThread().getName())
if __name__=='__main__':
t = Thread(target=task,name='线程1') # name 设置线程名
t.start()
t.setName('线程-1') # 设置线程名
print(t.getName()) # 获取线程名
print(t.is_alive(),t.isAlive())
t.join() # 等待线程执行完
print(t.isAlive())
print(currentThread().getName()) # 获取当前线程,在主线程下获取的就是主线程名
currentThread().setName('main线程') # 设置当前线程名
print('主线程',currentThread().getName())
print(active_count()) # 先导入active_count 查看活跃线程数目
print(enumerate()) # 先导入enumerate 查看线程守护线程
from threading import Thread
import time
def foo():
print(123)
time.sleep(1)
print('end123')
def bar():
print(456)
time.sleep(3)
print('end456')
if __name__=='__main__':
t1 = Thread(target=foo)
t2 = Thread(target=bar)
t1.setDaemon(True) # 等价于t1.daemon = True
t1.start()
t2.start()
print('--main--')守护线程等到非守护线程结束才结束。
互斥锁
from threading import Thread,Lock
import time
n = 100
def task():
global n
mutex.acquire()
temp = n
time.sleep(0.1)
n = temp - 1
mutex.release()
if __name__ == '__main__':
t_list = []
mutex = Lock()
for i in range(100):
t = Thread(target=task,)
t.start()
t_list.append(t)
for i in t_list:
i.join()
print(n)0
死锁
当两个线程互相争取对方现有的锁,就会造成死锁的现象。
递归锁
可以连续acquire多次,每acquire一次计数器加1,只有计数器为0时,其他线程才可以抢到该锁。
from threading import Thread,RLock
import time
mutexA = mutexB = RLock()
class MyThread(Thread):
def run(self):
self.f1()
self.f2()
def f1(self):
mutexA.acquire()
print('%s 拿到A锁'%self.name)
mutexB.acquire()
print('%s 拿到B锁' % self.name)
mutexB.release()
mutexA.release()
def f2(self):
mutexB.acquire()
print('%s 拿到B锁' % self.name)
time.sleep(3)
mutexA.acquire()
print('%s 拿到A锁' % self.name)
mutexA.release()
mutexB.release()
if __name__=='__main__':
for i in range(5):
t = MyThread()
t.start()Thread-1 拿到A锁
Thread-1 拿到B锁
Thread-1 拿到B锁
Thread-1 拿到A锁
Thread-2 拿到A锁
Thread-2 拿到B锁
Thread-3 拿到A锁
Thread-3 拿到B锁
Thread-3 拿到B锁
Thread-3 拿到A锁
Thread-5 拿到A锁
Thread-5 拿到B锁
Thread-2 拿到B锁
Thread-2 拿到A锁
Thread-4 拿到A锁
Thread-4 拿到B锁
Thread-5 拿到B锁
Thread-5 拿到A锁
Thread-4 拿到B锁
Thread-4 拿到A锁
信号量
有10个人上公共厕所,公共厕所只有五个坑,同一时间最多可以有五个人同时上厕所。
from threading import Thread,currentThread,Semaphore
import time,random
sem = Semaphore(5)
def task():
# sem.acquire()
# print('%s get'% currentThread().getName())
# sem.release()
with sem: # 与上边等价,这种方式更简洁
print('%s get' % currentThread().getName())
time.sleep(random.randint(1,5))
print('%s out' % currentThread().getName())
if __name__=='__main__':
for i in range(10):
t = Thread(target=task)
t.start()Thread-1 get
Thread-2 get
Thread-3 get
Thread-4 get
Thread-5 get
Thread-5 out
Thread-6 get
Thread-6 out
Thread-7 get
Thread-1 out
Thread-8 get
Thread-3 out
Thread-2 out
Thread-9 get
Thread-10 get
Thread-7 out
Thread-4 out
Thread-8 out
Thread-9 out
Thread-10 out
Event
from threading import Thread,Event
import time
event = Event()
def student(name):
print('%s 正在听课'% name)
event.wait() # 括号里面加上数字就是等待时间
print('%s 课间活动'% name)
def teacher(name):
print('%s 正在授课'%name)
time.sleep(7)
print('%s 下课' % name)
time.sleep(0.1)
event.set()
if __name__ == '__main__':
s1 = Thread(target=student,args=('rose',))
s2 = Thread(target=student, args=('lucy',))
s3 = Thread(target=student, args=('lily',))
t = Thread(target=teacher, args=('luli',))
s1.start()
s2.start()
s3.start()
t.start()rose 正在听课
lucy 正在听课
lily 正在听课
luli 正在授课
luli 下课
rose 课间活动
lily 课间活动
lucy 课间活动
# from threading import Thread,Event
# import time
# event = Event()
#
# def student(name):
# print('%s 正在听课'% name)
# event.wait() # 括号里面加上数字就是等待时间
# print('%s 课间活动'% name)
#
# def teacher(name):
# print('%s 正在授课'%name)
# time.sleep(7)
# print('%s 下课' % name)
# time.sleep(0.1)
# event.set()
#
#
# if __name__ == '__main__':
# s1 = Thread(target=student,args=('rose',))
# s2 = Thread(target=student, args=('lucy',))
# s3 = Thread(target=student, args=('lily',))
#
# t = Thread(target=teacher, args=('luli',))
#
# s1.start()
# s2.start()
# s3.start()
# t.start()
from threading import Thread,Event,currentThread
import time
event = Event()
def conn():
n=0
while not event.is_set(): # event 是否被设置
if n == 3:
print('%s try too many times'% currentThread().getName())
return
n += 1
event.wait(0.5)
print('%s try %s time'%(currentThread().getName(),n))
print('%s is connected'%currentThread().getName())
def check():
print('%s is checking'%currentThread().getName())
time.sleep(5)
event.set()
if __name__ =='__main__':
for i in range(3):
con = Thread(target=conn)
con.start()
check = Thread(target=check)
check.start()Thread-4 is checking
Thread-2 try 1 time
Thread-1 try 1 time
Thread-3 try 1 time
Thread-1 try 2 time
Thread-3 try 2 time
Thread-2 try 2 time
Thread-1 try 3 time
Thread-1 try too many times
Thread-2 try 3 time
Thread-3 try 3 time
Thread-3 try too many times
Thread-2 try too many times
定时器
验证码刷新
from threading import Timer
import random
class Code:
def __init__(self):
self.make_cache()
def make_cache(self,interval=10):
self.cache = self.make_code()
print(self.cache)
self.t = Timer(interval,self.make_cache) # 这个地方是函数名,如果是函数名()会报错
self.t.start()
def make_code(self,):
res = ''
for i in range(4):
s1=str(random.randint(0,9))
s2 = chr(random.randint(65,90)) # 大写字母
res += random.choice([s1,s2])
return res
def check(self):
while True:
code = input('验证码:').strip()
print('验证码 %s'%self.cache)
print('输入:%s'% code.upper())
if code.upper() == self.cache: # 不用区分大小写
print('正确')
self.t.cancel()
break
obj = Code()
obj.check()线程queue
多线程实现并发套接字通信
进程池线程池
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
import os,time,random
def task(name):
print('name:%s pid:%s'%(name,os.getpid()))
time.sleep(random.randint(1,3))
if __name__=='__main__':
pool = ThreadPoolExecutor(4)
for i in range(10):
pool.submit(task,'id %s'%i)
pool.shutdown() # 等待进程执行结束
print('主')name:id 0 pid:8892
name:id 1 pid:8892
name:id 2 pid:8892
name:id 3 pid:8892
name:id 4 pid:8892
主
以上代码实现的是线程池,如果实现进程池只要改一行代码:
Pool = ProcessPoolExecutor(4)就ok了
同步调用异步调用
同步调用
from concurrent.futures import ThreadPoolExecutor
import time,random
def work(name):
print('%s is working'%name)
time.sleep(random.randint(2,5))
res = random.randint(8,24)
return {'name':name,'hours':res}
def count(res):
name = res['name']
num = res['hours']*10
print('%s 制造了%s个艺术品'%(name,num))
if __name__ =='__main__':
pool = ThreadPoolExecutor(10)
worker1 = pool.submit(work,'1').result()
count(worker1)
worker2 = pool.submit(work, '2').result()
count(worker2)
worker3 = pool.submit(work, '3').result()
count(worker3)1 is working
1 制造了120个艺术品
2 is working
2 制造了240个艺术品
3 is working
3 制造了170个艺术品
异步调用
from concurrent.futures import ThreadPoolExecutor
import time,random
def work(name):
print('%s is working'%name)
time.sleep(random.randint(2,5))
res = random.randint(8,24)
return {'name':name,'hours':res}
def count(res):
res = res.result() # future对象此时已经执行完毕,获取future对象的结果
name = res['name']
num = res['hours']*10
print('%s 制造了%s个艺术品'%(name,num))
if __name__ =='__main__':
pool = ThreadPoolExecutor(10)
pool.submit(work,'1').add_done_callback(count) # 调用count方法并把结果future对象传给方法
pool.submit(work, '2').add_done_callback(count)
pool.submit(work, '3').add_done_callback(count)1 is working
2 is working
3 is working
3 制造了220个艺术品
2 制造了200个艺术品
1 制造了170个艺术品