目 录
一、线程相关理论
1、什么是线程?
线程是cpu调度的最小单位,能够独立运行。(进程是资源分配的最下单位,线程是CPU调度的最小单位)
进程:资源单位
线程:执行单位
如果将内存比作一个工厂的话,那进行就相当于一个车间,线程就是车间里面的流水线!
PS: 每个进程都自带一个线程,线程才是真正的执行单位,进程只是在代码运行过程中提供所需要的资源!
2、为什么需要线程?
开进程 1.申请内存空间 耗资源 2."拷贝代码" 耗资源 开线程 一个进程内可以起多个线程,并且线程与线程之间数据是共享的 ps:开启线程的开销要远远小于开启进程的开销
3、线程与进程之间有什么区别?
1)地址空间和其它资源(如打开文件):
进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。
2)通信:
3)调度和切换:
线程上下文切换比进程上下文切换要快得多。
4)在多线程操作系统中
进程不是一个可执行的实体。
二、创建线程的两种方法
使用模块:
from threading import thread
创建线程的注意事项:
# 开线程不需要在__main__代码块内 但是习惯性的还是写在__main__代码块内
方法一:
from threading import Thread import time def run(name): print('%s is coming..'%name) time.sleep(3) print('%s is over'%name) if __name__ == '__main__': t = Thread(target=run,args=('egon',)) t.start() # 告诉操作系统开辟一个线程 线程的开销远远小于进程,小到t.start()代码执行完 线程就已经开启了 print('主。。') ''' 执行结果: egon is coming.. 主。。 egon is over 为什么'egon is coming'子线程先执行,主线程后执行? '''
方法二:
from threading import Thread import time class MyThread(Thread): def __init__(self,name): super().__init__() self.name = name def run(self): print('%s is coming..' % self.name) time.sleep(3) print('%s is over'%self.name) # 不需要在 __main__ 下建立 t = MyThread('jason') t.start() print('主。。') ''' 执行结果: jason is coming.. 主。。 jason is over '''
三、线程对象及其方法
使用模块:
from threading import Thread, current_thread, active_thread
current_thread 获得当前线程的名字
active_thread 计算当前存活的进程数
注意:
线程之间是平等的关系,没有主次之分,我们只是认为的将其区分开!!!!
from threading import Thread,current_thread,active_count import time def test(name): print('%s is running..'%name) print('子线程current_thread',current_thread().name) # 获得子线程的名字 time.sleep(2) print('%s is ending'%name) t = Thread(target=test,args=('jason',)) # t = Thread(target=test,args=('jason,')) t.start() print('主。。') print('主线程current_thread',current_thread().name) # 获得主线程的名字
验证线程的os.getpid() 以及判断线程的存活数
代码如下:
from threading import Thread,current_thread,active_count import time import os def test(name,i): print('%s is running..'%name) print('子', os.getpid()) # 获取子线程的进程号 time.sleep(i) print('%s is ending'%name) t1 = Thread(target=test,args=('jason',1)) t2 = Thread(target=test,args=('egon',3)) # t = Thread(target=test,args=('jason,')) t1.start() t2.start() # t2.join() # 主进程等待子进程运行完毕。。。 # print('主。。',active_count()) # 1个线程 t1.join() # 主进程等待子进程运行完毕。。。 print('主。。',active_count()) # 2个线程 print('主',os.getpid()) # 获取主线程的进程号 —— 得知主线程和子线程的进程号相同,验证同属一个进程 ''' 执行结果如下: jason is running.. 子 9980 egon is running.. 子 9980 jason is ending 主。。 2 主 9980 egon is ending '''
四、线程间共享数据
线程间共享数据即多个线程操作同一份数据!
代码验证:
from threading import Thread money = 1000 def run(): global money money = 999 t = Thread(target=run) t.start() print(money) # 999 说明主线程和子线程两者共享数据,即操作同一份数据
五、守护线程 ******
from threading import Thread,current_thread import time def run(i): print(current_thread().name) time.sleep(i) print('GGGGGG') t1 = Thread(target=run,args=(1,)) t2= Thread(target=run,args=(3,)) t1.daemon = True # 设置守护线程!!!!!! t1.start() t2.start() print('主。。') ''' 执行结果: Thread-1 Thread-2 主。。 GGGGGG GGGGGG ''' ''' 提出问题:为什么主线程结束了,守护线程还可以执行? 主线程的结束也就意味着进程的结束 主线程必须等待其他非守护线程的结束才能结束 (意味子线程在运行的时候需要使用进程中的资源,而主线程一旦结束了资源也就销毁了) '''
六、线程互斥锁
代码示例:
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)
代码释义:
我们先开了100个线程,为了达到并发的效果,我们将开启的100个线程添加到列表中,然后在循环列表里的线程为线程加 join方法来确保每个线程都可以执行完毕!!
小例子:
from threading import Thread from multiprocessing import Process 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-------")