python-多线程

发布于:2022-12-02 ⋅ 阅读:(265) ⋅ 点赞:(0)

线程介绍

线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。每一个程序都至少有一个线程,那就是程序本身。
  线程是程序中一个单一的顺序控制流程。在单个程序中同时运行多个线程完成不同的工作,称为多线程。

使用多线程是为了提高程序的运行效率

线程实现

使用threading模块

普通创建方式

# 导入threading模块
import threading

# 定义一个函数
def add(x,y):
    print(x + y)
 # 新建一个线程
t = threading.Thread(target=add, args=(1,2,))
# 线程启动
t.start()

结果为3

自定义线程

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

import threading

class MyThread(threading.Thread):
    def __init__(self,x,y):        
        super(MyThread, self).__init__()  # 重构run函数必须要写
        self.x = x
        self.y = y

    def run(self):
      print(self.x + self.y)

t = MyThread(1,2)
t.start()

结果还是3

守护线程

我们看下面这个例子,这里使用setDaemon(True)把所有的子线程都变成了主线程的守护线程,因此当主进程结束后,子线程也会随之结束。所以当主线程结束后,整个程序就退出了。

# 导入threading模块
import threading
# 定义一个函数
def add(x,y):
    print(x + y) 
# 新建一个线程
t = threading.Thread(target=add, args=(1,2,))
t.setDaemon(True)   #把子进程设置为守护线程,必须在start()之前设置
# 线程启动
t.start()

主线程等待子线程结束

# 导入threading模块
import threading
# 定义一个函数
def add(x,y):
    print(x + y) 
# 新建一个线程
t = threading.Thread(target=add, args=(1,2,))
# 线程启动
t.start()
t.join() # 设置主线程等待子线程结束

多线程共享全局变量

# 导入threading模块
import threading
import time
g_num = 1
# 定义一个函数
def add1(num):
    global g_num
    g_num = g_num + num    
    print(g_num)
 
def add2(num):
    global g_num    
    g_num = g_num + num            
    print(g_num)
# 新建一个线程# 
t1 = threading.Thread(target=add1, args=(1,))
t2 = threading.Thread(target=add2, args=(2,))
# 线程启动
t1.start()
#延时一会,保证t1线程中的事情做完
time.sleep(1)
t2.start()

结果为:

2
4

互斥锁

当多个线程同时修改同一条数据时可能会出现脏数据,所以,出现了线程锁,即同一时刻允许一个线程执行操作。线程锁用于锁定资源

导入线程模块,通过threading.Lock() 创建互斥锁.

里面有两个方法
acquire()— 锁定资源,此时资源是锁定状态,其他线程无法修改锁定的资源,直到等待锁定的资源释放之后才能操作;
release()— 释放资源,也称为解锁操作,对锁定的资源解锁,解锁之后其他线程可以对资源正常操作;

# 导入threading模块
import threading
import time
# 声明全局变量
g_num = 1
# 创建互斥锁
lock = threading.Lock()
# 定义一个函数
def add1():
    global g_num 
    for i in range(0,100):
        # 锁定资源
        lock.acquire()   
        g_num = g_num + 1
        # 解锁资源
        lock.release()       
    print(g_num)
     
def add2():
    global g_num
    for i in range(0,100):
        # 锁定资源
        lock.acquire()        
        g_num = g_num + 1   
        # 解锁资源
        lock.release()             
    print(g_num)
    
# 新建一个线程
t1 = threading.Thread(target=add1)
t2 = threading.Thread(target=add2)
# 线程启动
t1.start()
t2.start()
# 阻塞函数,等待线程结束
t1.join()
t2.join()

结果:

100
200

信号量(BoundedSemaphore类)

互斥锁同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据

import threading
import time

bs = threading.BoundedSemaphore(5)  # 最多允许5个线程同时运行

def run(n):
    bs.acquire()   #加锁   
    time.sleep(1)    
    print("run the thread:%s\n" % n)    
    bs.release()     #释放
for i in range(0,20):
    t  = threading.Thread(target=run, args=(i,))
    t.start()

运行结果发现是5个线程5个线程的打印

事件(Event类)

  • clear 将flag设置为“False”
  • set 将flag设置为“True”
  • is_set 判断是否设置了flag
  • wait 会一直监听flag,如果没有检测到flag就一直处于阻塞状态
    事件处理的原理:全局定义了一个Flag,当flag值为False,那么event.wait()就会阻塞,当flag值为True,那么event.wait()便不再阻塞。
import threading
import time
event = threading.Event()

def before():
    print("准备工作")
    event.set() # 设置开始工作
    time.sleep(5)
    event.clear()
   

def work():
    if event.is_set():#判断是否设置了标志位
    while 1:
        event.wait()
        print("工作中!!!")
        time.sleep(1)
            if event.wait(3):                
                pass            
            else:                
                print("工作结束")                
                break

before = threading.Thread(target=before,)
work = threading.Thread(target=work,)   before.start()
work.start()
before.join()
work.join()

结果:
在这里插入图片描述

其它的方法

threading方法

方法 功能
active_count() , activeConut() 返回处于alive状态的Thread对象数量
current_thread() , currentThread() 返回当前的Thread对象
get_ident() 返回当前线程的线程标识符。线程标识符是一个非负整数,并无特殊函数,只是用来标识线程,该整数可能会被循环利用。python3.3及以后版本支持该方法
enumerate() 返回当前处于alive状态的所有Thread对象列表
stack_size([size]) 返回创建线程时使用的栈的大小,如果指定size参数,则用来指定后续创建的线程使用的栈大小,size必须是0(表示使用系统默认值)或大于32K的正整数。
main_thread() 返回主线程对象,即启动python解释器的线程对象。python3.4及以后版本支持该方法
本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到