一、进程
二、线程
1,使用Thread类创建线程
#!/usr/bin/env python # -*- coding:utf-8 -*- __author__ = 'zhoufeng' import threading import time def f1(arg): time.sleep(5) print(arg) t=threading.Thread(target=f1,args=(123,)) #target表示让线程干什么活,args是参数 t.start() #线程进入准备状态,等待CPU调度 print('end') ''' 输出如下: end 123 ''' #主线程执行到最后了 但程序未退出,在等待子程序执行完
2,主线程默认是等待子线程执行完毕后再退出的,也可以通过setDaemon方法设置成主线程不等待子线程
#!/usr/bin/env python # -*- coding:utf-8 -*- __author__ = 'zhoufeng' import threading import time def f1(arg): time.sleep(5) print(arg) t=threading.Thread(target=f1,args=(123,)) #target表示让线程干什么活,args是参数 t.setDaemon(True) #设置主线程不等子线程 t.start() #线程进入准备状态,等待CPU调度 print('end') ''' 输出如下: end ''' #主线程执行完后就退出了
3,前面的setDaemon方法只能决定等不等待子线程执行完,更为灵活的join方法能指定在什么位置等待,最多等待多久(即便子进程未执行完也继续往下执行)
#!/usr/bin/env python # -*- coding:utf-8 -*- __author__ = 'zhoufeng' import threading import time def f1(arg): time.sleep(5) print(arg) t=threading.Thread(target=f1,args=(123,)) t.setDaemon(True) t.start() t.join(2) #表示主线程执行到这里暂停,等待子进程执行,最多等待2秒 print('end') ''' 输出如下: end ''' #在本例中无法等待子进程执行完毕,子进程耗时5秒,而主进程只会等待2秒 #join方法和setDaemon方法不冲突
4,另外一种创建线程的方法
#!/usr/bin/env python # -*- coding:utf-8 -*- __author__ = 'zhoufeng' import threading class MyTread(threading.Thread): #自定义线程类,继承Thread类 def __init__(self,func,args): #重写__init__方法 self.func=func self.args=args super(MyTread,self).__init__() #执行父类的__init__方法 def run(self): #重写run方法 self.func(self.args) def f2(arg): print(arg) obj=MyTread(f2,123) #实例化一个线程对象 obj.start() #执行线程对象的start方法,等待cpu调度
5,线程锁
线程锁相当于在电话亭排队打电话,一次只让一个人进去,后面的人等着
不加锁的情况,会发现多个线程会同时修改数据,导致脏数据
#!/usr/bin/env python # -*- coding:utf-8 -*- __author__ = 'zhoufeng' import threading import time NUM=10 def func(): global NUM #在函数内(更低的作用域)修改全局变量,需要声明此处操作的是全局变量 NUM-=1 time.sleep(2) print(NUM) for i in range(10): t=threading.Thread(target=func,) t.start() #输出结果如下: ''' 0 0 0 0 0 0 0 0 0 0 '''
如果多个线程去做同一个操作,对该操作加锁之后,必须等上一个线程处理完,下一个线程才能开始处理
#!/usr/bin/env python # -*- coding:utf-8 -*- __author__ = 'zhoufeng' import threading import time NUM=10 def func(l): global NUM #在函数内(更低的作用域)修改全局变量,需要声明此处操作的是全局变量 l.acquire() #上锁 NUM-=1 time.sleep(2) print(NUM) l.release() #开锁 lock=threading.RLock() for i in range(10): t=threading.Thread(target=func,args=(lock,)) t.start() #输出结果如下: ''' 9 8 7 6 5 4 3 2 1 0 '''
6,信号量
信号量相当于排队玩过山车 ,一共30个人,一次只让5个人上去
#!/usr/bin/env python # -*- coding:utf-8 -*- __author__ = 'zhoufeng' import threading import time NUM=10 def func(l,i): global NUM #在函数内(更低的作用域)修改全局变量,需要声明此处操作的是全局变量 l.acquire() #上锁 NUM-=1 time.sleep(2) print(NUM,i) l.release() #开锁 lock=threading.BoundedSemaphore(5) #使用BoundedSemaphore类创建信号量对象,5表示每次允许5个线程执行 for i in range(30): t=threading.Thread(target=func,args=(lock,i)) t.start()
7,事件
事件相当于过马路,出现绿灯后,所有人都可以过去
#!/usr/bin/env python # -*- coding:utf-8 -*- __author__ = 'zhoufeng' import threading def func(i,e): print(i) e.wait() #程序暂停,检查是什么灯(事件是否发生),红灯停,绿灯行 print(i+100) event=threading.Event() #定义一个事件对象 for i in range(10): t=threading.Thread(target=func,args=(i,event)) t.start() event.clear() #设置成红灯,默认是红灯 inp=input(">>>>") ": event.set() #设置成绿灯
8,线程池
#!/usr/bin/env python # -*- coding:utf-8 -*- __author__ = 'zhoufeng' #线程池用于控制并发线程数,因为不是线程数越多越好,最好等于CPU核心数,减少上下文切换带来的开销 #python中无线程池类,需要自定义 #让我想起了shell中的管道用法 import threading import queue import time class ThreadPool: #定义一个线程池类 def __init__(self,maxsize=5): self.maxsize=maxsize self._q=queue.Queue(maxsize) #定义一个队列,能放5个元素 for i in range(maxsize): self._q.put(threading.Thread) #将线程类放入队列 def get_thread(self): #取队列元素:返回一个线程类 return self._q.get() def add_thread(self): #放入元素 self._q.put(threading.Thread) pool=ThreadPool(5) #创建线程池对象 def task(arg,p): print(arg) time.sleep(1) p.add_thread() #执行完一个任务就往线程池中再放入一个元素 for i in range(100): t=pool.get_thread() #如果线程池中已无元素,程序会夯住 obj=t(target=task,args=(i,pool,)) obj.start()