一、线程定义及作用
线程:进程线程其实都是虚拟单位,都是用来帮助我们形象的描述某种事物
进程:资源单位(进程开辟一块内存空间,里面可以有多个线程)
线程:执行单位(进程的任务都是线程去执行)
将内存比如成工厂
那么进程就相当于是工厂里面的车间
而你的线程就相当于是车间里面的流水线
ps:每个进程都自带一个线程,线程才是真正的执行单位,进程只是在线程运行过程中
提供代码运行所需要的资源
线程的作用:
开进程:
1.申请内存空间 耗资源
2."拷贝代码" 耗资源
开线程:
一个进程内可以起多个线程,并且线程与线程之间数据是共享的
ps:开启线程的开销要远远小于开启进程的资源占有
比如:一个进程在运行过程中遇到阻塞,要么只能等待,
要么就需要多启动一个进程去执行提高运算速度,
这时候 线程 就可以在不多开启进程的情况下,异步去执行其他代码,提高效率
(进程在同一时间只能干一件事,要想同时干几件事就显得无能为力)
注意:进程是资源分配的最小单位,线程是cpu调度的最小单位
每一个进程中至少有一个线程
二、创建线程的两种方式
from threading import Thread import time def task(name): print('%s is running' % name) time.sleep(3) print('%s is over' % name) # 开线程不需要在__main__代码块内 但是习惯性的还是写在__main__代码块内 t = Thread(target=task, args=('egon',)) t.start() # 告诉操作系统开辟一个线程 线程的开销远远小于进程 # 小的代码执行完 线程就已经开启了 print('主') """第二种方法: from threading import Thread import time class MyThread(Thread): def __init__(self, name): super().__init__() self.name = name def run(self): print('%s is running' % self.name) time.sleep(3) print('%s is over' % self.name) t = MyThread('egon') t.start() print('主') 就是继承Thread得来"""
三、线程对象及其他方法
子线程与子线程,主线程都是异步(同时)运行,并且都是同一个进程
from threading import Thread, current_thread, active_count import time, os def task(name, i): print("%s is runing" % name) print("子线程名字:", current_thread().name) # 子线程名字 print("子线程进程:", os.getpid()) time.sleep(1) print("%s is over" % name) # active_count() 当前活跃线程数: # current_thread().name 线程名字(是主线程或子线程名字)
# os.getpid()查询进程数
t1 = Thread(target=task, args=("engon", 1,)) t2 = Thread(target=task, args=("tank", 2,)) t1.start() t2.start() # t1.join() # t2.join() #等待子线程结束 print("当前正在活跃的线程数:", active_count()) print("主线程名字:", current_thread().name) # print("主线程进程:", os.getpid()) # 只要不是子线程,都是主线程
四、守护线程
主线程的结束也就意味着进程的结束
主线程必须等待其他非守护线程的结束才能结束
(意味子线程在运行的时候需要使用进程中的资源,而主线程一旦结束了资源也就销毁了)
from threading import Thread, current_thread import time def task(i): print(current_thread().name) time.sleep(i) print('GG') # for i in range(3): # t = Thread(target=task,args=(i,)) # t.daemon = True # t.start() t = Thread(target=task, args=(1,)) t.daemon = True # 开启子线程守护线程 t.start() print('主')
五、线程之间的通讯
同一个进程里,所有线程的数据都是共享的,因为都在同一个内存空间(进程开辟的空间)
from threading import Thread money = 666 def task(): global money money = 777 t = Thread(target=task) t.start() t.join() print(money) #777
六、线程锁(互斥锁)
线程锁:和进程锁使用方法一样,开启多线程中会存在数据不安全(多个线程抢同一个数据)
from threading import Thread, Lock import time n = 100 def task(mutex): global n mutex.acquire() tmp = n time.sleep(0.1) n = tmp - 1 mutex.release() t_list = [] mutex = Lock() for i in range(100): t = Thread(target=task, args=(mutex,)) t.start() t_list.append(t) for t in t_list: t.join() print(n) #0 # 100个线程异步去执行task(),拿到锁以后一个一个运行,保证数据安全
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.daemon = True t1.start() t2.start() print("main-------")