Python中的多线程

本文深入探讨多线程编程的基本概念,包括主线程与子线程的交互、多线程速度提升、线程冲突及解决方案、基于类实现多线程等核心主题。通过实例代码,解析如何使用Python进行多线程编程,涵盖线程冲突、死锁、信号量和屏障的处理技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、主线程与小弟线程

代码:

import _thread   # 多线程
import win32api

def show(i):
    # 0 代表系统,你要开心代表内容,来自马小妹代表标题,0代表窗口类型0,1,2,3
    mystr = win32api.MessageBox(0,"你要开心","来自马小妹的问候",0)

for i in range(5):   # 这是小弟线程
    _thread.start_new_thread(show,(i,))  # 前面是执行函数,后面是一个元组,可以不写前提是函数没有形参

while True:  # 在这里加入死循环是为了脚本主线程不死,小弟线程才能运行
    pass

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

二、多线程的速度

代码:

import _thread
import time
def go():
    for i in range(5):
        print(i,"-------")
        time.sleep(1)

for i in range(2):   # 同时执行2次
    _thread.start_new_thread(go,())

for j in range(5): # 让主线程卡顿5秒
    time.sleep(1)

print("over")

#  运行结果:
#  0 -------
#  0 -------
#  1 -------
#  1 -------
#  2 -------
#  2 -------
#  3 -------
#  3 -------
#  4 -------
#  4 -------
#  over

注意:
1、进程中有许多线程
2、线程是资源共享的,谁先抢到谁先运行
3、while True: …pass关掉,则什么都不会出来
4、线程依赖于进程,而进程之间是相互独立的
5、如果主进程死掉则线程也会死掉

三、线程冲突

代码:

import _thread

num = 0
def add():
    for _ in range(1000000):
        global num
        num += 1
    print(num)
'''
for j in range(5):
    add()
'''
for i in range(5):
    _thread.start_new_thread(add,())
# 这里就是线程冲突,5个线程同时抢夺num的资源,导致最后结果错误

while True:  # 防止主线程不死
    pass 

#  运行结果:
#  1086754
#  996579
#  1261015
#  1161017
#  1408389

包_thread不灵活,最好不用
**结果错误:**因为"NUM += 1"加的可能并不是本线程的(抢占资源)
线程比进程消耗少,可以多建几个,但也不能太多

四、基于类实现多线程

代码:

import threading
import win32api


class Mythread(threading.Thread):   # 继承threading.Thread类
    def run(self):  # 重写threading.Thread类中的run函数
        win32api.MessageBox(0,"hello",'Tom',0)

for i in range(5):  # 同时创建5个线程
    t = Mythread()  # 初始化
    t.start()  # 开启


while True:
    pass

运行结果:
在这里插入图片描述
过程:继承、初始化、重写run(原来在类里)、if、创建五个线程、启动线程、卡死主进程
**每个线程都正确:**重写self.num

五、类线程顺序风格

import threading
import win32api

class Mythread(threading.Thread):   # 继承threading.Thread类
    def run(self):  # 定义函数
        win32api.MessageBox(0,"hello",'Tom',0)

for i in range(5):
    t = Mythread()  # 初始化
    t.start()  # 开启
    # 等待一个线程执行完毕,再执行下一个线程,一方面可以阻止脚本主线程死掉,另一方面也可以防止线程冲突的一种办法
    t.join()
# t.join() 如果将其放在外部的不确定因素是,系统给for 循环和下面的代码锁定了一片内存,当循环执行完成之后,
# 内存就开锁了,但是里面的东西还依然存在,所以才结束一个窗体,game over就出来了,
# 就和删除文件后,内存中可能还有文件一样的道理

print("game over")

运行结果
在这里插入图片描述

六、类线程的乱序风格

代码:

import threading
import win32api

class Mythread(threading.Thread):  # 继承threading.Thread类
    def __init__(self, num):
        threading.Thread.__init__(self)  # 父类初始化
        self.num = num

    def run(self):  # 定义函数
        win32api.MessageBox(0, "hello" + str(self.num), 'joker', 0)
        print(self.getName())  # 获取线程名

Mythd = []
for i in range(5):
    t = Mythread(i)  # 初始化
    print(i)
    t.start()  # 开启
    Mythd.append(t)  # 将乱序线程(同时抢夺run这个函数)加入列表

for j in Mythd:
    # 这里与顺序不同,上面显示所有的线程都加入Mthd列表(所以一次性跳出5个窗口,但是主线程还没死,因为有join卡住)。
    # j是线程
    j.join()  # 这里主线程同时等待所有线程都执行完毕,才执行“game over”
print("game over")

"""
运行结果:
0
1
2
3
4
Thread-4
Thread-2
Thread-5
Thread-3
Thread-1
game over
"""

七、基于类解决线程冲突

代码:

import threading

num = 0
mutex = threading.Lock()  # 创建一个锁,threading.Lock()是一个类

class Myhtread(threading.Thread):
    def run(self):
        global num
        if mutex.acquire(1):  # 如果锁成功,那么线程继续干活,如果锁失败,下面的线程一直等待锁成功,1,代表独占
            for i in range(1000):  # 数字小的时候还是不会产生线程冲突的
                num += 1
            mutex.release()  # 释放锁,一定切记
        print(num)

mythread = []
for i in range(5):
    t = Myhtread()
    t.start()
    mythread.append(t)

for thread in mythread:
    thread.join()  # 或者直接将thread.join()加入for i in range(5),也能解决线程冲突,但是貌似就变成单线程了

print("game over")

"""
运行结果:
1000
2000
3000
4000
5000
game over
"""

八、死锁

代码:

import threading
import time

boymutex = threading.Lock()  # 创建一个锁
girlmutex = threading.Lock()  # 创建一个锁

class boy(threading.Thread):
    def run(self):
        if boymutex.acquire(1):  # 锁定成功就继续执行,锁定不成功,就一直等待
            print(self.name + "boy  say i  am sorry   up")
            # time.sleep(3)  # 时间过短的话也可以并发执行,不会锁死

            if girlmutex.acquire(1):  # 锁定不成功,因为下面已经锁定
                print(self.name + "boy  say i  am sorry   down")
                girlmutex.release()
            boymutex.release()

class girl(threading.Thread):
    def run(self):
        if girlmutex.acquire(1):  # 锁定成功就继续执行,锁定不成功,就一直等待
            print(self.name + "girl say i  am sorry  up")
            # time.sleep(3)

            if boymutex.acquire(1):  # 锁定不成功,同理上面已经锁定一直等待
                print(self.name + "girl say i  am sorry  down")
                boymutex.release()
            girlmutex.release()

# 开启两个线程
# boy1 = boy()   

for i in range(1000):
    boy().start()
    girl().start()

"""
运行结果:
Thread-1boy  say i  am sorry   up
Thread-2girl say i  am sorry  up
"""

九、Rlock

代码:

import threading

num = 0
mutext = threading.RLock()  # PLOCK避免单线程死锁

class Mythreading(threading.Thread):
    def run(self):
        global num
        if mutext.acquire(1):
            num += 1
            print(self.name, num)
            if mutext.acquire(1):
                num += 1000
                mutext.release()

            mutext.release()

for i in range(5):  # 开启5个进程
    t = Mythreading()
    t.start()

"""
运行结果:
Thread-1 1
Thread-2 1002
Thread-3 2003
Thread-4 3004
Thread-5 4005
"""

十、创建多线程

1.用函数创建多线程(需要处理让脚本主线程不死)
代码:

import threading
import win32api


class Mythread(threading.Thread):  # 继承threading.Thread类
    def run(self):  # 定义函数
        win32api.MessageBox(0, "hello", 'Tom', 0)

Mythd = []
for i in range(5):
    t = Mythread()  # 初始化
    print(i)
    t.start()  # 开启
    Mythd.append(t) # 将乱序线程(同时抢夺run这个函数)加入列表

for j in Mythd:
    # 这里与顺序不同,上面显示所有的线程都加入Mthd列表(所以一次性跳出5个窗口,但是主线程还没死,因为有join卡住)。
    # j是线程
    j.join() # 这里主线程同时等待所有线程都执行完毕,才执行“game over”
print("game over")

"""
运行结果:
0
1
2
3
4
game over
"""

十一、信号限制线程数量

代码:

import threading

import time

sem = threading.Semaphore(2)  # 限制最大线程数为2个
def gothread():
    with sem:  # 锁定数量
        for i in range(10):
            print(threading.current_thread().name, i)  # 打印线程名字
            time.sleep(1)


for i in range(5):
    threading.Thread(target=gothread).start()  # 乱序执行多线程,就可以考虑为有些cpu牛逼些能够执行快一点

"""
运行结果:
Thread-1 0
Thread-2 0
Thread-1 1
Thread-2 1
Thread-1 2
Thread-2 2
Thread-1 3
Thread-2 3
Thread-1 4
Thread-2 4
Thread-2 5
Thread-1 5
Thread-1 6
Thread-2 6
Thread-1 7
Thread-2 7
Thread-2 8
Thread-1 8
Thread-1 9
Thread-2 9
Thread-3 0
Thread-4 0
Thread-3 1
Thread-4 1
Thread-3 2
Thread-4 2
Thread-3 3
Thread-4 3
Thread-4 4
Thread-3 4
Thread-3 5
Thread-4 5
Thread-3 6
Thread-4 6
Thread-4 7
Thread-3 7
Thread-3 8
Thread-4 8
Thread-3 9
Thread-4 9
Thread-5 0
Thread-5 1
Thread-5 2
Thread-5 3
Thread-5 4
Thread-5 5
Thread-5 6
Thread-5 7
Thread-5 8
Thread-5 9

十二、锁定匹配数量

代码:

import threading

bar = threading.Barrier(2)

def sever():
   print(threading.current_thread().name,"start")
    bar.wait()
    print(threading.current_thread().name,"end")

for i in range(3):
    threading.Thread(target=sever).start()

"""
运行结果:
Thread-1 start
Thread-2 start
Thread-2 end
Thread-1 end
Thread-3 start
"""
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值