一、线程
1、概念
-
线程
在一个进程的内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”叫做线程
是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
线程通常叫做轻型的进程。线程是共享内存空间的并发执行的多任务,每一个线程都共享一个进程的资源
线程是最小的执行单元,而进程由至少一个线程组成。如何调度进程和线程,完全由操作系统决定,程序自己不能决定什么时候执行,执行多长时间
-
多线程
是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。
-
主线程:
任何进程都会有一个默认的主线程 如果主线程死掉 子线也程也死掉 所以 子线程依赖于主线程
-
GIL(了解)
其他语言,CPU 是多核是支持多个线程同时执行。但在 Python 中,无论是单核还是多核,同时只能由一个线程在执行。其根源是 GIL 的存在。
GIL 的全称是 Global Interpreter Lock(全局解释器锁),来源是 Python 设计之初的考虑,为了数据安全所做的决定。某个线程想要执行,必须先拿到 GIL,我们可以把 GIL 看作是“通行证”,并且在一个 Python 进程中,GIL 只有一个。拿不到通行证的线程,就不允许进入 CPU 执行。
并且由于 GIL 锁存在,Python 里一个进程永远只能同时执行一个线程(拿到 GIL 的线程才能执行),这就是为什么在多核CPU上,Python 的多线程效率并不高的根本原因。
-
模块
_thread模块:低级模块
threading模块:高级模块,对_thread进行了封装
2、使用_thread 模块 去创建线程
-
导入模块
import _thread
-
开启线程
_thread.start_new_thread(函数名,参数)
-
注意:
- 参数必须为元组类型
- 如果主线程执行完毕 子线程就会死掉
- 如果线程不需要传参数的时候 也必须传递一个空元组占位
-
实例
import win32api import _thread #引入线程的模块 比较老的模块 新的 threading def run(i): win32api.MessageBox(0,"您的{}号大宝贝上线了".format(i),"来自凤姐以及陆源凯的问候",2) for i in range(5): _thread.start_new_thread(run,(i,)) #发起多个线程 传参的情况 参数为元组 # _thread.start_new_thread(run,()) #发起多个线程 不传参 页需要俩个参数 第二个为空元组 print('会先执行我') #如果主线程 不死 那么 所有的次线程 就都会正常执行 while True: pass
提高效率
import _thread import time def run(): for i in range(10): print(i,'------------') time.sleep(1) """ for i in range(5): #50秒 run() """ for i in range(5): _thread.start_new_thread(run,()) #发起五个线程去执行 时间大大缩短 for i in range(10): #循环10秒 计算 线程执行完毕所需要的时间 类似与一个劫停 time.sleep(1) print('xxxx')
3、threading创建线程(重点)
-
导入模块
import threading
-
threading创建线程的方式
myThread = threading.Thread(target=函数名[,args=(参数,),name=“你指定的线程名称”])
参数
- target:指定线程执行的函数
- name:指定当前线程的名称
- args:传递各子线程的参数 ,(元组形式)
-
开启线程
myThread.start()
-
线程等待
myThread.join()
-
返回当前线程对象
-
threading.current_thread()
-
threading.currentThread()
-
-
获取当前线程的名称
- threading.current_thread().name
- threading.currentThread().getName()
-
设置线程名
setName()
Thread(target=fun).setName('name')
-
返回主线程对象
threading.main_thread()
-
获取当前活着的所有线程总数,包括主线程main
threading.active_count() 或 threading.activeCount()
-
判断线程是不是活的,即线程是否已经结束
-
Thread.is_alive()
-
Thread.isAlive()
-
-
线程守护
设置子线程是否随主线程一起结束
有一个布尔值的参数,默认为False,该方法设置子线程是否随主线程一起结束 True一起结束
Thread.setDaemon(True)
还有个要特别注意的:必须在start() 方法调用之前设置
if __name__ == '__main__': t = Thread(target=fun, args=(1,)) t.setDaemon(True) t.start() print('over')
-
获取当前所有的线程名称
threading.enumerate() # 返回当前包含所有线程的列表
4、启动线程实现多任务
import time
import threading
def run1():
# 获取线程名字
print("启动%s子线程……"%(threading.current_thread().name))
for i in range(5):
print("lucky is a good man")
time.sleep(1)
def run2(name, word):
print("启动%s子线程……" % (threading.current_thread().name))
for i in range(5):
print("%s is a %s man"%(name, word))
time.sleep(1)
if __name__ == "__main__":
t1 = time.clock()
# 主进程中默认有一个线程,称为主线程(父线程)
# 主线程一般作为调度而存在,不具体实现业务逻辑
# 创建子线程
# name参数可以设置线程的名称,如果不设置按顺序设置为Thread-n
th1 = threading