【Python】python多线程

1. 进程与线程的概念

1.1 进程

进程:进程是操作系统进行资源分配和调度运行的基本单位,一个正在运行的程序就是一个进程。

查看进程的两种方法:

  • 打开Windows任务管理器
  • 打开cmd,输入命令tasklist

1.打开Windows任务管理器如下:Google Chrome这个应用,后面有数字(24),代表这个应用正在运行24个进程。

在这里插入图片描述

2.打开cmd,输入命令tasklist如下:

在这里插入图片描述

1.2 线程

线程:线程是程序执行的最小单元,进程负责分配资源,而线程是使用分配的资源去执行程序。

  • 进程是线程的容器,一个进程下最少有一个线程。
  • 一个进程下的所有线程,共享该进程的所有资源。

2. threading模块

1.threading模块的方法:

方法 描述
threading.currentThread() 返回当前的线程变量
threading.enumerate() 返回一个包含正在运行的线程列表
threading.activeCount() 返回正在运行的线程数量

2.threading模块的Thread类的方法:

方法 描述
run() 用以表示线程活动的方法
start() 启动线程活动
join() 等待至线程中止
isAlive() 返回线程是否活动的
getName() 返回线程名
setName() 设置线程名

3.threading模块的Lock类的方法:

方法 描述
acquire() 获得锁
release() 释放锁

2.1 threading模块的方法

2.2 多线程的创建与使用

1.通过threading.Thread()创建对象,并使用多线程。

import threading

def test1():
    for i in range(1,6):
        print(i)

def test2(x,y):
    for i in range(x,y):
        print(i)

if __name__=="__main__":
    t1 = threading.Thread(name='thread1', target=test1) # name的值为线程名,target的值为函数名
    t2 = threading.Thread(name='thread2', target=test2, args=(11,16)) # args的值为函数的传参
    t1.start() # 启动线程thread1
    t2.start() # 启动线程thread2

运行结果:

1
2 
11
12
3 
4 
13
14
15
5 

1.从运行结果可以看出,多线程是并发的
2.多运行几次程序,会发现每次运行结果不一致

2.通过继承threading.Thread类,然后重写__init__()方法和run()方法,再创建对象,并使用多线程。

import threading

class myThread(threading.Thread):
    def __init__(self, name, target):
        threading.Thread.__init__(self)
        self.name = name
        self.target = target
        
    def run(self):
        print("启动线程: {}".format(self.name))
        self.target()
        
def test1():
    for i in range(1,6):
        print(i)

def test2():
    for i in range(11,16):
        print(i)

if __name__=="__main__":
    t1 = myThread(name='thread1', target= test1)
    t2 = myThread(name='thread2', target= test2)
    t1.start()
    t2.start()

运行结果:

启动线程: thread1
1
启动线程: thread2
11
12
13
14
2
15
3
4
5

2.3 主线程与守护线程

主线程:主线程会等待所有的子线程运行结束后,再结束。
守护线程:当设置一个线程为守护线程后,随着主线程的结束,守护线程也会跟着结束。

例1:一个主线程,两个子线程。

  • 设置子线程1为守护线程;
  • 主线程先后调用子线程1和子线程2;
  • 构造子线程1的运行时间大于子线程2;
  • 主线程等待两个子线程运行,子线程2先运行结束,子线程1本来也还在运行,但由于主线程和子线程2都结束了,作为守护线程的子线程1也跟着结束。
import threading
import time

def test1():
    print("Hello World")
    time.sleep(2)
    print("Hello World")

def test2():
    for i in range(1,6):
        print(i)

if __name__=="__main__":
    t1 = threading.Thread(name='thread1', target=test1) 
    t2 = threading.Thread(name='thread2', target=test2) 
    t1.daemon = True # 设置守护线程
    t1.start()
    t2.start()

运行结果:

Hello World
1
2
3
4
5

1.注意:设置守护线程要在放在线程启动之前,即t.daemon = True要放在t.start()之前。
2.看结果可以发现,本来子线程thread1要打印两次Hello World,但是因为主线程和子线程thread2都运行结束了,thread1作为守护线程,也跟着结束了,所以第二次Hello World没有打印。

例2:一个主线程,两个子线程。

  • 子线程1无限循环,设置子线程1为守护线程;
  • 子线程2运行时间有限;
  • 相当于子线程2运行结束,子线程1就跳出了无限循环。
import threading
import time
from datetime import datetime

def test1():
    while True:
        print(datetime.now())
        time.sleep(0.5)

def test2():
    for i in range(1,6):
        print(i)
        time.sleep(0.5)

if __name__=="__main__":
    t1 = threading.Thread(name='thread1', target=test1) 
    t2 = threading.Thread(name='thread2', target=test2) 
    t1.daemon = True # 设置守护线程
    t1.start()
    t2.start()

运行结果:

2022-11-04 22:38:41.222094
1
2022-11-04 22:38:41.733547
2
3
2022-11-04 22:38:42.241197
2022-11-04 22:38:42.751068
4
2022-11-04 22:38:43.253057
5

2.4 线程阻塞

使用join()可以实现线程阻塞,从而控制线程运行的先后顺序。

注:

  1. join()不设置时间,则等待线程结束后,再执行后续代码。
  2. join(3)设置时间3秒,则等待线程执行3秒后,再执行后续代码。

1.等待执行线程1结束后,再执行主线程和线程2。

import threading

def test1():
    for i in range(1,6):
        print(i)

def test2(x,y):
    for i in range(x,y):
        print(i)

if __name__=="__main__":
    t1 = threading.Thread(name='thread1', target=test1) 
    t2 = threading.Thread(name='thread2', target=test2, args=(11,16)) 
    t1.start() 
    t1.join() # 等待线程thread1结束后,再执行后续代码
    t2.start()   
    print("hello world")
    

运行结果:

1
2
3
4
5
11
hello world
12
13
14
15

2.等待执行线程1结束后,再等待执行线程2结束,最后执行主线程。

import threading

def test1():
    for i in range(1,6):
        print(i)

def test2(x,y):
    for i in range(x,y):
        print(i)

if __name__=="__main__":
    t1 = threading.Thread(name='thread1', target=test1) 
    t2 = threading.Thread(name='thread2', target=test2, args=(11,16)) 
    t1.start() 
    t1.join() # 等待线程thread1结束后,再执行后续代码
    t2.start()  
    t2.join() # 等待线程thread2结束后,再执行后续代码
    print("hello world")
    

运行结果:

1
2
3
4
5
11
12
13
14
15
hello world

3.等待执行线程1运行3秒后,再执行主线程和线程2。

import threading
import time

def test1():
    for i in range(1,6):
        print(i)
        time.sleep(1)

def test2(x,y):
    for i in range(x,y):
        print(i)

if __name__=="__main__":
    t1 = threading.Thread(name='thread1', target=test1) 
    t2 = threading.Thread(name='thread2', target=test2, args=(11,16)) 
    t1.start() 
    t1.join(3) # 等待线程thread1运行3秒后,再执行后续代码
    t2.start()  
    print("hello world")

运行结果:

1
2
3
11
hello world
12
13
14
15
4
5

2.5 线程同步

多个线程同时运行,由于多线程是并发的,各个线程之间会互相抢占计算资源,导致程序混乱。
如果多个线程共同对某个数据修改,可能会出现数据不同步的问题,为了保证数据的正确性,需要进行多线程同步。

使用threading.Lock(),可以对线程进行上锁和解锁,从而实现程同步,其中:

  • acquire()方法用于给线程上锁
  • release()方法用于给线程解锁

1.未对线程上锁,并对变量number进行修改,运行后发现很混乱,不符合预期结果。

import threading

number = 0

def update_number():
    global number 
    print("old number:{}".format(number))  
    number += 10
    print("new number:{}".format(number))
    print("---------------")


if __name__=="__main__":
    # 创建5个线程,添加进列表
    threadList = []
    for i in range(5):
        t = threading.Thread(target=update_number) 
        threadList.append(t) 
    # 依次启动5个线程
    for t in threadList:
        t.start() 

运行结果:

old number:0
new number:10
old number:10
new number:20
---------------
---------------
old number:10
new number:30
---------------
old number:20
new number:40
---------------
old number:40
new number:50
---------------

2.对线程上锁,并对变量number进行修改,运行后符合预期结果。

import threading

number = 0
threadLock = threading.Lock() # 创建Lock对象

def update_number():
    threadLock.acquire() # 获得锁
    global number 
    print("old number:{}".format(number))  
    number += 10
    print("new number:{}".format(number))
    print("---------------")
    threadLock.release() # 释放锁

if __name__=="__main__":
    # 创建5个线程,添加进列表
    threadList = []
    for i in range(5):
        t = threading.Thread(target=update_number) 
        threadList.append(t) 
    # 依次启动5个线程
    for t in threadList:
        t.start() 

运行结果:

old number:0
new number:10
---------------
old number:10
new number:20
---------------
old number:20
new number:30
---------------
old number:30
new number:40
---------------
old number:40
new number:50
---------------

猜你喜欢

转载自blog.csdn.net/aidijava/article/details/127624072