1.什么是线程?
线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
一句话就是:线程是一堆指令的执行。是操作系统最小的调度单位, 是一串指令的集合。
2.线程与进程。
现在先不详细讨论进程。只是简单理解下进程和线程之间的联系。
进程是对cpu的资源集合。里面包含对各种资源的调用,内存的管理,网络接口的调用等
打个比喻,进程好似一个工厂,里面设配齐全,但是如果需要工厂工作运行起来,必须有人。人就是线程,负责处理执行一切工作。
2.1 上下文切换:
cpu一颗核心,只能在同一时间干一件事。但是,我们经常在使用电脑时怎么就可以同时打开多个软件呢?
这是因为cpu的运算速度太快了超过了人类眼睛所能看出差别的速度,我们在电脑上看到打开多个软件时,实际上,这是幻觉,它们在调度器上排着队,进行着上下文切换。
3.多线程的优点
3.1 使用线程可以把占据长时间的程序中的任务放到后台去处理。
3.2 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度
3.3 程序的运行速度可能加快
3.4 在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。
其他:但是线程不是越多就越好,越多的线程有可能拖慢程序的运行。比如线程多了,cpu处理上下文是消耗的资源就多。
4.Python中使用线程有两种方式:函数或者用类来包装线程对象。
4.1 函数方式使用:
import threading,time """定义线程去执行的任务函数""" def run(s): print('start',time.time()) print(s) time.sleep(2) print('end',time.time()) for num in range(1,5): value = 'num{0}'.format(num) """启动一个线程,执行目标任务是run(),args传值""" threaobj = threading.Thread(target=run,args=(value,)) threaobj.start() """ print--- start 1527040747.327816 num1 start 1527040747.327816 num2 start 1527040747.327816 num3 start 1527040747.327816 num4 end 1527040749.3279305 end 1527040749.3279305 end 1527040749.3279305 end 1527040749.3279305 """
4.2 类继承方式使用。
import threading,time """ 类继承的写法。 用等待线程全部结束的思路得出程序执行时间。 """ """定义线程类,并继承 threading.Thread""" class myThread(threading.Thread): def __init__(self,n): super(myThread,self).__init__() self.n = n """定义执行函数。run()名字不能修改""" def run(self): print(self.n) time.sleep(2) strat_time = time.time() """将所有的线程记录在列表,利用join()等待所有线程执行完毕,获取从程序开始到所有线程执行完毕所花费的时间""" thread_obj =[] for num in range(1,5): tobj = myThread(num) tobj.start() thread_obj.append(tobj) for iteam in thread_obj: iteam.join() print('cost:',time.time()-strat_time)
4.3 额外:查看当前线程。
import threading,time # 实例:查看当前线程 class Mythread(threading.Thread): def __init__(self,num): super(Mythread,self).__init__() self.num = num def run(self): print('-----',self.num,'------',threading.current_thread()) time.sleep(2) for i in range(1,6): t = Mythread(i) t.start() # 当前主线程 print(threading.current_thread()) # 当前活动的线程数 print(threading.active_count())
4.4.守护线程。
import threading,time class myThread(threading.Thread): def __init__(self,n): super(myThread,self).__init__() self.n = n def run(self): print(self.n) time.sleep(2) print('done....',self.n) strat_time = time.time() thread_obj =[] for num in range(1,5): tobj = myThread(num) """ 设置当前线程为守护线程。即是,主线程启动线程之后,便不管线程了,主线程继续执行。 但是主线程一旦结束,就算子线程还未执行完毕,也会一起结束。 """ tobj.setDaemon(True) # tobj.start() time.sleep(2) # 这个例子可以看到,程序已经不等time.sleep(2)了。 print('cost:',time.time()-strat_time)
5. 线程锁。
线程同时修改同一份数据时必须加锁,mutex互斥锁
所以,threading 提供了两种锁,threading.Lock 和 threading.RLock。
5.1 全局线程锁
import threading """ 线程锁的实例。 查看每一个线程修改数据之前加锁会得到什么结果。 """ def run(): global count print('get count:{0}'.format(count)) """加锁""" global_lock.acquire() count -= 10 """释放""" global_lock.release() if __name__ == '__main__': count = 999 thread_lists = [] """生成全局锁""" global_lock = threading.Lock() for i in range(10): t = threading.Thread(target=run, ) t.start() thread_lists.append(t) for iteam in thread_lists: iteam.join() print('end... count:{0}'.format(count))
5.2 线程递归锁
.
import threading,time def run1(): print("grab the first part data") lock.acquire() global num num +=1 lock.release() return num def run2(): print("grab the second part data") lock.acquire() global num2 num2+=1 lock.release() return num2 def run3(): lock.acquire() res = run1() print('--------between run1 and run2-----') res2 = run2() lock.release() print(res,res2) if __name__ == '__main__': num,num2 = 0,0 lock = threading.RLock() for i in range(10): t = threading.Thread(target=run3) t.start() while threading.active_count() != 1: print(threading.active_count()) else: print('----all threads done---') print(num,num2)
6.多线程之间的交互,Event()
import threading import time import os """ 两个线程之间的通信。 Event() 根据event事件判断 event = threading.Event() event.set() 设置一个标志位 event.clear() 清除 event.is_set() 是否设置 event.wait() 等待 """ event = threading.Event() # 设置事件 def lighter(): '''红绿灯''' count = 1 while True: time.sleep(1) if count<11: """设置红灯标志""" event.set() print('\033[1;31m 红灯 \033[0m',count) elif count>10 and count<=20: """清除标志""" event.clear() print('\033[1;32m 绿灯 \033[0m',count) else: count = 1 continue count += 1 def car(): """ 车流事件 红灯停,绿灯走 :return: """ while True: time.sleep(1.2) car_num = 'car' if not event.is_set(): print(car_num,'going....') else: print(car_num,'waiting....') t = threading.Thread(target=lighter,) t.start() car = threading.Thread(target=car) car.start()