1. python线程概念:
    线程也叫轻量级进程,是操作系统能够进行运算调度的最小单位,它被包涵在进程之中,是进程中的实际运作单位。线程不拥有竞争系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其他线程共享进程所拥有的全部资源。一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行
  2. 使用多线程的优处:
    进程之间不能共享内存,但线程之间共享内存非常容易
    操作系统在创建进程时,需要为该进程重新分配系统资源,但创建线程的代价则小得多。线程比进程的并发性高
    python语言内置了多线程功能支持,而不是单纯地作为底层操作系统的调度方式,从而简化了python的多线程编程

线程主要是_thread和threading模块

标准库_thread模块其实是start_new_thread方法:语法格式_thread.start_new_thread(function,
args[,kwargs]) 参数列表args是执行函数,可选的kwargs参数只指定关键字参数的字典

  1. 普通创建
import time
import datetime
import _thread

date_time_format = "%H:%M:%S"


def get_time_str():
    now = datetime.datetime.now()
    return datetime.datetime.strftime(now, date_time_format)  # 时间格式化为ISO来输出


def thread_function(thread_id):
    print("Thread %d\t start at %s" % (thread_id, get_time_str()))  # \t空四个字符(\n\t换行空四个字符),%d对应线程号thread_id
    # %s对应时间get_time_str()
    print("Thread %d\t sleeping" % thread_id)
    time.sleep(4)  # sleep函数推迟调用线程的运行,通过参数secs指秒数来表示线程挂起的时间。
    print("Thread %d\t finish at %s" % (thread_id, get_time_str()))


def main():
    print("Main thread start at %s" % get_time_str())
    for i in range(5):
        # _thread模块中start_new_thread方法提供简单的多线程机制,单个线程执行时别的线程也在同步执行
        _thread.start_new_thread(thread_function, (i,))
    time.sleep(6)  # 主线程添加secs=6目的是让主线程不要立马执行完退出,主线程退出则其它线程无论是否执行完都要被强制退出
    print("Main thread finish at %s" % get_time_str())


if __name__ == "__main__":
    main()
  • 输出为:结果是顺序的,但是可能出现乱序,两行输出结果相叠的情况。

Main thread start at 21:57:02
Thread 0 start at 21:57:02
Thread 0 sleeping
Thread 4 start at 21:57:02Thread 3 start at 21:57:02
Thread3 sleeping
Thread 1 start at 21:57:02Thread 2 start at 21:57:02
Thread 2 sleeping

Thread 1 sleeping

Thread 4 sleeping
Thread 4 finish at 21:57:06Thread 2 finish at 21:57:06
Thread 1 finish at 21:57:06Thread 0 finish at 21:57:06

Thread 3 finish at 21:57:06

Main thread finish at 21:57:08

  1. _thread.allocate_lock方法返回一个Lock对象:常见方法有acquire、release和locked

由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,当多个线程同时修改同一条数据时可能会出现脏数据, 所以出现了线程锁(主线程可以在其它线程执行完后立即退出),即同一时刻允许一个线程执行操作。线程锁用于锁定资源,可以定义多个锁,像下面的代码,当需要独占 某一个资源时,任何一个锁都可以锁定这个资源,就好比你用不同的锁都可以把这个相同的门锁住一样。 由于线程之间是进行随机调度的,如果有多个线程同时操作一个对象,如果没有很好地保护该对象,会造成程序结果的不可预期, 我们因此也称为“线程不安全”。 为了防止上面情况的发生,就出现了互斥锁(Lock)

import time
import datetime
import _thread

date_time_format = "%H:%M:%S"


def get_time_str():
    now = datetime.datetime.now()
    return datetime.datetime.strftime(now, date_time_format)  # 时间格式化为ISO来输出


def thread_function(thread_id, lock):
    print("Thread %d\t start at %s" % (thread_id, get_time_str()))  # \t空四个字符(\n\t换行空四个字符),%d对应线程号thread_id
    # %s对应时间get_time_str()
    print("Thread %d\t sleeping" % thread_id)
    time.sleep(4)  # sleep函数推迟调用线程的运行,通过参数secs指秒数来表示线程挂起的时间。
    print("Thread %d\t finish at %s" % (thread_id, get_time_str()))
    lock.release()  # release方法用于释放锁,释放前线程必须处于锁定状态,可以不在同一个线程中释放锁.


def main():
    print("Main thread start at %s" % get_time_str())
    locks = []
    for i in range(5):
        lock = _thread.allocate_lock()
        lock.acquire()  # 无条件获取锁定Look对象,等待它被另一个线程释放(一次只有一个线程可以获取锁定)
        locks.append(lock)
    for i in range(5):
        _thread.start_new_thread(thread_function, (i, locks[i]))  # 启动一个线程并返回其标识符
        time.sleep(1)
    for i in range(5):
        while locks[i].locked():  # 用于返回锁的状态,如果已被某个线程锁定,则返回True否则返回False
            time.sleep(1)
    print("Main thread finish at %s" % get_time_str())


if __name__ == "__main__":
    main()

输出为:
Main thread start at 22:43:28
Thread 0 start at 22:43:28
Thread 0 sleeping
Thread 1 start at 22:43:29
Thread 1 sleeping
Thread 2 start at 22:43:30
Thread 2 sleeping
Thread 3 start at 22:43:32
Thread 3 sleeping
Thread 0 finish at 22:43:32
Thread 4 start at 22:43:33
Thread 4 sleeping
Thread 1 finish at 22:43:34
Thread 2 finish at 22:43:34
Thread 3 finish at 22:43:36
Thread 4 finish at 22:43:37
Main thread finish at 22:43:38

  1. 自定义线程:继承threading.Thread来定义线程类,其本质是重构Thread类中的run方法
import time
import datetime
import threading

date_time_format = "%H:%M:%S"


def get_time_str():
    now = datetime.datetime.now()
    return datetime.datetime.strftime(now, date_time_format)  # 时间格式化为ISO来输出


class MyThread(threading.Thread):  # 子类调用父类threading.Thread

    def __init__(self, thread_id):
        super(MyThread, self).__init__()  # 用super()方法来调用父类的__init__()构造方法
        self.thread_id = thread_id  # 初始化属性

    def run(self):
        print("Thread %d\t start at %s" % (self.thread_id, get_time_str()))  # \t空四个字符(\n\t换行空四个字符),%d对应线程号thread_id
        # %s对应时间get_time_str()
        print("Thread %d\t sleeping" % self.thread_id)
        time.sleep(4)  # sleep函数推迟调用线程的运行,通过参数secs指秒数来表示线程挂起的时间。
        print("Thread %d\t finish at %s" % (self.thread_id, get_time_str()))


def main():
    print("Main thread start at %s" % get_time_str())
    threads = []
    # 创建线程
    for i in range(5):
        thread = MyThread(i)  # 创建子类MyThread的对象并赋予参数i
        threads.append(thread)  # 用append()在列表threads后面追加元素
    # 启动线程
    for i in range(5):
        threads[i].start()
        time.sleep(1)
    # 等待线程执行完毕
    for i in range(5):
        threads[i].join()
    print("Main thread finish at %s" % get_time_str())


if __name__ == "__main__":
    main()

输出为:
Main thread start at 22:16:33
Thread 0 start at 22:16:33
Thread 0 sleeping
Thread 1 start at 22:16:34
Thread 1 sleeping
Thread 2 start at 22:16:35
Thread 2 sleeping
Thread 3 start at 22:16:36
Thread 3 sleeping
Thread 0 finish at 22:16:37
Thread 4 start at 22:16:37
Thread 4 sleeping
Thread 1 finish at 22:16:38
Thread 2 finish at 22:16:39
Thread 3 finish at 22:16:40
Thread 4 finish at 22:16:41
Main thread finish at 22:16:41

  1. 队列:Queue类实现了一个基本的先进先出(FIFO)容器,使用put()将元素添加到队列尾端,使用get()从队列尾部移除元素。
from queue import Queue

q = Queue()  # 创建Queue()的对象
for i in range(5):
    q.put(i)  # 将元素加入q序列的尾端
while not q.empty():  # while语句满足队列不为空执行下面代码
    print(q.get())  # 将元素从队列中移除并输出来

输出为:
0
1
2
3
4