一、理论基础

单线程:独立的任务挨个运行
多线程:独立的任务同时运行。底层是将一个大任务分多线程,线程流水线式运行

举例:假定有两个循环函数。一个需10秒运行结束,另一个需12秒运行结束
单线程:挨个运行,共需22秒运行结束
多线程:同时运行,共需12秒运行结束(以时间长的子线程运行时间为准)
不使用锁:主线程自定义等待时间(足够所有子线程运行结束),等待时间结束后主线程继续运行
-----注意!如果不自定义等待时间,则可能主线程运行结束了子线程还没运行完
使用锁:主线程不用自定义时间,子线程运行结束后释放锁,主线程立即继续运行
不使用守护线程:主线程若退出,则子线程无论是否运行结束都会强制退出
使用守护线程:主线程若退出,受守护的子线程不会退出,不受守护的子线程强制退出

使用模块及语法:

import thread                 #不推荐使用,适合高级底层专家使用
import threading              #更高级、更全面。推荐使用
import Queue                  #可以创建队列数据结构,使其在多线程之间共享

threading模块中的对象(类):

方法

解释

Thread

表示一个执行线程的对象

Lock

锁原语对象

RLock

可重入锁对象,使单一线程可以(再次)获得已持有的锁(递归锁)

Condition

条件变量对象,使得一个线程等待另一个线程满足特定的“条件”

Event

条件变量的通用版本,任意数量的线程等待某个事件的发生,在该事件发生后所有线程将被激活

Semaphore

为线程间共享的有限资源提供了一个“计数器”,如果没有可用资源时会被阻塞

BoundedSemaphore

与Semaphore相似,不过它不允许超过初始值

Timer

与Thread相似,不过它要在运行前等待一段时间

threading模块中thread类的对象和方法:

Thread对象数据属性

方法

解释

name

线程名

ident

线程的标识符

daemon

布尔标志,表示这个线程是否是守护线程

Thread对象方法

方法

解释

init()

实例化一个线程对象。注意是单下划线

start()

开始执行该线程

run()

定义线程功能的方法(通常在子类中被应用开发者重写)

join(timeout=None)

直至启动的线程终止之前一直挂起;除非赋予等待值,否则会一直阻塞

threading模块中的其它函数:

方法

解释

enumerate()

返回当前活动的Thread对象列表

settrace(func)

为所有线程设置一个trace函数

setprofile(func)

为所有线程设置一个profile函数

stack_size(size=0)

返回新创建线程的栈大小;或为后续创建的线程设定栈的大小为size

Queue模块的常用属性: Queue模块的类

方法

解释

Queue(最大值)

创建一个先入先出队列。如果给定最大值,则在队列没有空间时阻塞;否则为无限队列

LifoQueue(最大值)

创建一个后入先出队列。如果给定最大值,则在队列没有空间时阻塞;否则为无限队列

PriorityQueue(最大值)

创建一个优先级队列。如果给定最大值,则在队列没有空间时阻塞,否则为无限队列

Queue异常

方法

解释

Empty

当对空队列调用get*()方法时抛出异常

Full

当对已满的队列调用put*()方法时抛出异常

Queue对象方法

方法

解释

qsize()

返回队列大小(该值为近似值)

empty()

如果队列为空,则返回 True;否则,返回 False

full()

如果队列已满,则返回 True;否则,返回 False

put(item,block,timeout)

将item 放入队列。若block为 True且timeout为None,则在有可用空间之前阻塞;如果timeou为正值,则最多阻塞 timeout秒;如果block为False,则抛出Empty异常

put_nowait(item)

和 put(item,False)相同

get(block,timeout)

从队列中取得元素。如果给定了block,则一直阻塞到有可用的元素为止

get_nowait()

和 get(False)相同

task_done()

用于表示队列中的某个元素已执行完成,该方法会被下面的join()使用

join()

在队列中所有元素执行完毕并调用上面的task_done()信号之前,保持阻塞

多线程编程相关模块:

方法

解释

thread

基本的、低级别的线程模块

threading

高级别的线程和同步对象

multiprocessing

使用“threading”接口派生/使用子进程

subprocess

完全跳过线程,使用进程来执行

Queue

供多线程使用的同步先入先出队列

mutex

互斥对象

SocketServer

创建/管理线程控制的TCP/UDP服务器

串讲—Python程序的执行顺序: 以最外面的代码由上至下执行,函数/类代码没有顺序,只有在调用他们的时候执行。

二、使用Threading模块创建线程

代码实例:

#! /usr/bin/python
# -*- coding: UTF-8 -*-

import threading                                #导入模块
from time import sleep,ctime

loops=(12,8)                                    #变量赋值。分别是12秒和8秒

class mythread(threading.Thread):               #定义类。继承父类
    def __init__(self,func,args,name=''):       #定义类内的初始函数(__init__函数),用于接收传参
        threading.Thread.__init__(self)         #父类(Thread)中的初始函数的声明
        self.name=name                          #将函数参数转换为类内全局变量
        self.func=func     
        self.args=args
        
    def run(self):                              #定义表示线程活动的函数
        self.func(*self.args)                   #全局声明

def loop(nloop,nsec):                           #定义函数。有两个变量(括号里致使变量名而已)
    print ("\n循环%s,开始时间为:%s" % (nloop,ctime()))
    sleep(nsec)
    print ("循环",nloop,"完成时间:",ctime())
        
def main():                                     #定义主函数
    print ("开始:",ctime())                     #开始时间。即时取时
    threads=[]                                  #定义了一个空列表。列表名为threads
    nloops=range(len(loops))                    #len(loops)=2,range(len(loops))=[0,1]。即两个列表值
    
    for i in nloops:                            #第一个循环
        t = mythread(loop,(i,loops[i]),loop.__name__)        #定义实参了
        threads.append(t)                       #整个类加进来了
    for i in nloops:                            #第二个循环
        threads[i].start()                      #启动线程活动
    for m in nloops:                            #第三个循环
        threads[m].join()                       #等待线程终止
    print ("都已完成:",ctime())

if __name__=="__main__":                        #独立运行脚本的惯用方法,判断函数是否为主程序
    main()

-----------------------------------------------------------------
输出结果如下:
开始: Mon Mar 30 17:19:25 2020
循环0,开始时间为:Mon Mar 30 17:19:25 2020
循环1,开始时间为:Mon Mar 30 17:19:25 2020
循环 1 完成时间: Mon Mar 30 17:19:33 2020
循环 0 完成时间: Mon Mar 30 17:19:37 2020
都已完成: Mon Mar 30 17:19:37 2020

代码实例:

#! /usr/bin/python
# -*- coding: UTF-8 -*-
 
import threading
import time

exitFlag = 0
 
class myThread (threading.Thread):                 #继承父类threading.Thread
    def __init__(self, threadID, name, counter):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.counter = counter
    def run(self):                                 #把要执行的代码写到run函数里面线程在创建后会直接运行run函数 
        print ("开始" + self.name)
        print_time(self.name, self.counter,5)      #调用函数。同时对函数传入实参
        print ("退出" + self.name)
 
def print_time(threadName, delay, counter):        #定义函数。有三个形参(括号里只是变量名而已),接收实参传入
    while counter:
        if exitFlag:                               #if语句,和代码头处的想对应
            threading.Thread.exit()                #退出
        time.sleep(delay)
        print ("%s: %s" % (threadName, time.ctime(time.time())))
        counter -= 1                               #counter=counter-1
 
thread1 = myThread(1, "xiancheng-1", 1)            #创建新线程。类的实例化,传递三个参数给类,类接收
thread2 = myThread(2, "xiancheng-2", 2)
 
thread1.start()                                    #开启线程
thread2.start()
 
print ("退出主线程")

-----------------------------------------------------------------
输出结果如下:
开始xiancheng-1
开始xiancheng-2
退出主线程
xiancheng-1: Mon Mar 30 17:24:11 2020
xiancheng-2: Mon Mar 30 17:24:12 2020
xiancheng-1: Mon Mar 30 17:24:12 2020
xiancheng-1: Mon Mar 30 17:24:13 2020
xiancheng-2: Mon Mar 30 17:24:14 2020
xiancheng-1: Mon Mar 30 17:24:14 2020
xiancheng-1: Mon Mar 30 17:24:15 2020
退出xiancheng-1
xiancheng-2: Mon Mar 30 17:24:16 2020
xiancheng-2: Mon Mar 30 17:24:18 2020
xiancheng-2: Mon Mar 30 17:24:20 2020
退出xiancheng-2