多线程

160 阅读3分钟

一、概念

1.1 线程

在一个进程的内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”叫做线程

是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程

线程通常叫做轻型的进程。线程是共享内存空间的并发执行的多任务,每一个线程都共享一个进程的资源

线程是最小的执行单元,而进程由至少一个线程组成。如何调度进程和线程,完全由操作系统决定,程序自己不能决定什么时候执行,执行多长时间

1.2 多线程

是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理(Chip-level multithreading)或同时多线程(Simultaneous multithreading)处理器。

1.3 主线程

任何进程都会有一个默认的主线程,如果主线程死掉,子线也程也死掉,所以子线程依赖于主线程。

1.4 GIL(了解)

其他语言,CPU 是多核是支持多个线程同时执行。但在 Python 中,无论是单核还是多核,同时只能由一个线程在执行。其根源是 GIL 的存在。

GIL 的全称是 Global Interpreter Lock(全局解释器锁),来源是 Python 设计之初的考虑,为了数据安全所做的决定。某个线程想要执行,必须先拿到 GIL,我们可以把 GIL 看作是“通行证”,并且在一个 Python 进程中,GIL 只有一个。拿不到通行证的线程,就不允许进入 CPU 执行。

并且由于 GIL 锁存在,Python 里一个进程永远只能同时执行一个线程(拿到 GIL 的线程才能执行),这就是为什么在多核CPU上,Python 的多线程效率并不高的根本原因。

二、threading创建线程(重点)

2.1 导入模块

import threading

2.2 threading创建线程模式

myThread = threading.Thread(target=函数名[,args=(参数,),name='你指定的线程名称']

参数:

  • target: 指定线程执行的函数
  • name: 指定当前线程的名称
  • args: 传递各子线程的参数,(元祖形式)

2.3 开启线程

myThread.start()

2.4 线程等待

myThread.join()

2.5 返回当前线程对象

  • threading.current_thread()
  • threading.currentThread()

2.6 获取当前线程的名称

  • threading.current_thread().name
  • threading.currentThread().getName()

2.7 设置线程名

myThread = threading.Thread(target=fun).setName('name')

2.8 返回主线程对象

threading.main_thread()

2.9 获取当前活着的所有线程总数,包括主线程main

  • threading.active_count()
  • threading.activeCount()

2.10 判断线程是不是活的,即线程是否已经结束

  • myThread.is_alive()
  • myThread.isAlive()

2.11 线程守护

设置子线程是否随主线程一起结束。 有一个布尔值的参数,默认为False,该方法设置子线程是否随主线程一起结束 True一起结束。

if __name__ == "__main__":
    t = threading.Thread(target=fun, args=(1,))
    t.setDaemon(True)
    t.start()
    print('over')

2.12 获取当前所有的线程名称

threading.enumerate()

三、启动线程实现多任务

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.Thread(target=run1, name="th1")
    th2 = threading.Thread(target=run2, args=("lucky", "nice"))

    #启动
    th1.start()
    th2.start()

    #等待子线程结束
    th1.join()
    th2.join()

    t2 = time.clock()
    print("耗时:%.2f"%(t2-t1))