线程

线程简介

  • 在一个进程中,若想做多个子任务,我们把这些子任务称为线程。
  • 线程可以理解为轻量级的进程。
  • 进程之间的数据是独立的,而一个进程下的线程数据是共享的。
  • 线程是 CPU 分配的最小单位。 进程和线程的调度都是操作系统的事。
  • 一个进程默认有一个线程,我们称为主线程。

线程模块

  • _thread低级模块
  • threading高级模块,是对 _thread 的封装
  • 以后建议大家使用高级模块 threading

线程模块 _thread

  • 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    import _thread
    import time


    def loop():
    print('子线程开始')
    print('子线程结束')


    if __name__ == '__main__':
    print('主线程开始')
    # 创建线程
    _thread.start_new_thread(loop, ())
    # 主线程结束,子线程立即结束,通过延时测试
    time.sleep(3)
    print('主线程结束')

    非常简陋,不建议使用

线程模块 threading

  • 基本使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    import time
    import threading


    def run(num):
    c = threading.current_thread()
    time.sleep(3)
    print('子线程开始', c.name)
    print(num)
    print('子线程结束', c.name)


    if __name__ == '__main__':
    # 获取主线程
    t = threading.main_thread()
    print('主线程开始:', t.name)
    # 获取当前线程
    # c = threading.current_thread()
    # print('当前线程:', c.name)

    # 创建子线程
    sub = threading.Thread(target=run, args=(250,), name='下载美女图片')
    # 启动子线程
    sub.start()
    # 活跃线程个数
    # print(threading.active_count())
    # 线程列表
    # print(threading.enumerate())

    time.sleep(1)
    # 判断线程是否是活着的
    print(sub.is_alive())

    # 等待子线程
    sub.join()
    print(sub.is_alive())
    print('主线程结束:', t.name)

数据共享

  • 示例 1:全局变量可以共享

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    import threading

    # 全局变量
    num = 250


    def thread_one():
    global num
    num += 10


    def thread_two():
    global num
    num -= 100


    if __name__ == '__main__':
    print('主线程:', num)

    t1 = threading.Thread(target=thread_one)
    t1.start()
    t1.join()
    print('主线程:', num)

    t2 = threading.Thread(target=thread_two)
    t2.start()
    t2.join()
    print('主线程:', num)

    线程之间共享进程的所有数据

  • 示例 2:多线程操作同一变量,可能会出错。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    import threading

    # 这是你银行的存款
    money = 250


    def run(n):
    global money
    for i in range(100000):
    # 运算之后数据应该不变
    money += n
    money -= n


    if __name__ == '__main__':
    while True:
    t1 = threading.Thread(target=run, args=(10,))
    t2 = threading.Thread(target=run, args=(15,))
    t1.start()
    t2.start()
    t1.join()
    t2.join()

    if money != 250:
    break

    print(money)
  • 示例 3:加锁解决数据错乱问题 (线程锁)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    import threading

    # 这是你银行的存款
    money = 250


    def run(n):
    global money
    for i in range(100000):
    '''
    lock.acquire()
    try:
    # 运算之后数据应该不变
    money += n
    money -= n
    finally:
    lock.release()
    '''
    # 简化书写
    with lock:
    money = money + n
    money = money - n


    if __name__ == '__main__':
    lock = threading.Lock()
    while True:
    t1 = threading.Thread(target=run, args=(10,))
    t2 = threading.Thread(target=run, args=(15,))
    t1.start()
    t2.start()
    t1.join()
    t2.join()

    if money != 250:
    break

    print(money)

自定义线程类

  • 说明:需要继承自 Thread 类,还需要重写 run 方法,开启线程时自动调用 run 方法
  • 示例:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    import time
    from threading import Thread


    class MyTtread(Thread):
    def __init__(self, t):
    super().__init__()
    self.t = t

    def run(self):
    for i in range(3):
    print('子线程中...')
    time.sleep(self.t)


    if __name__ == '__main__':
    print('主线程开始')
    p = MyTtread(2)
    p.start()
    p.join()
    print('主线程结束')

定时线程

  • 说明:threading 模块中,有一个 Timer 类,继承自 Thread 类,可以延迟执行线程任务。
  • 示例:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import os
    import threading


    def run():
    os.system('start notepad++')


    if __name__ == '__main__':
    # 延迟指定时间才会执行的任务
    t = threading.Timer(3, run)
    t.start()
    t.join()

信号传递(Event)

  • 说明:通常用于控制线程的执行
  • 示例:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    import time
    import threading


    def run(num):
    for i in range(num):
    # 等待条件成立,会阻塞
    e.wait()
    print('第%d步' % (i + 1))
    # 清除条件
    e.clear()


    if __name__ == '__main__':
    e = threading.Event()
    threading.Thread(target=run, args=(3,)).start()

    for i in range(3):
    time.sleep(1)
    # 设置后,wait处将不再阻塞
    e.set()
    print('走你,', end=' ')