写python博客的第七天 线程的点点点

本文深入探讨了Python中多线程编程的技巧与实践,包括线程资源共享、冲突解决、顺序执行、死锁预防及线程数量控制等关键概念。

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

就算失败了99次,也要努力继续。。。凑个整!

线程是资源共享的,在执行时,谁抢到了CPU谁就先执行

主线程与多线程

import _thread  #多线程  后面会用threading
import win32api

def show(i):
    #0代表系统,第一个 " " 代表内容,第二个" "代表标题,后面0代表窗口类型0,1,2,3
    mystr = win32api.MessageBox(0,"美好的一天,又完事了","来自win32问候",1)

for i in range(5):   #创建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(3):  #三个线程同时执行
    _thread.start_new_thread(go,())

for j in range(6):  #让主线程睡6秒
    time.sleep(6)

print('over')
"""
结果   
0 ----
0 ----
0 ----
1 ----
1 ----
1 ----
2 ----
2 ----
2 ----
3 ----
3 ----
3 ----
4 ----
4 ----
4 ----
over
"""


多线程冲突

import threading

num = 0
def add():
    for _ in range(1000000):
        global num # 全局变量就点global
        num +=1 
    print(num)

for i in range(4):
    threading._start_new_thread(add,())
   # 这里就是线程冲突,4个线程同时抢夺num的资源,导致最后结果错误 
"""
1460085
1477139
1104212
1130832
"""
while True:   #让主线程不死
    pass

基于类实现多线程

import threading
import win32api

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

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

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

在这里插入图片描述

线程可以按顺序执行

import threading
import win32api

class mytheard(threading.Thread): # 继承threading.Thread类
    def run(self): # 定义函数, 重写threading.Thread类中的run函数
        win32api.MessageBox(0,'hello','tyler',3)

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

类线程的乱序

import threading
import win32api

class mythread(threading.Thread):
    def __init__(self,num):
        threading.Thread.__init__(self)  # 父类初始化
        self.num = num
    
    def run(self):
        win32api.MessageBox(0, "hello" + str(self.num), 'tyler', 1)
        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-2
Thread-3
Thread-5
Thread-1
Thread-4
game over
"""

用类解决线程的冲突

给线程上锁,这样多线程就相当于单线程了

import threading

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


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

lis = []
for i in range(5):
    t = mytheard()
    t.start()
    lis.append(t)

for theard in lis:
    theard.join()   # 或者直接将thread.join()加入for i in range(5),也能解决线程冲突,但是貌似就变成单线程了
print('game over')
"""
100
200
300
400
500
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()   # Thread-1boy 第一个线程
# boy1.start()
# girl1 = girl()
# girl1.start()
'''
这种例子时间过短是无法很好的产生死锁
for i in range(10):
    Mythread1().start()
    Mythread2().start()

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

Rlock锁

Lock与Rlock两种琐的主要区别是:RLock允许在同一线程中被多次acquire。而Lock却不允许这种情况。注意:如果使用RLock,那么acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正释放所占用的琐

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()


创建多线程的几种方法

'''
第一种用函数创建多线程,但是需要处理让脚本主线程不死
import threading
import win32api


class Mythread(threading.Thread):  # 继承threading.Thread类
    def run(self):  # 定义函数
        win32api.MessageBox(0, "hello", 'joker', 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")

'''

'''
第二种是基于类继承创建多线程
import threading
import win32api


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


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


while True:
    pass
'''
'''

def show(i):

    win32api.MessageBox(0,"这是一个测试","来自Joker",0)

threading.Thread(target=show,args=(i,)).start()  # 切记这里的args是一个元组
threading.Thread(target=show,args=(i,)).start()
'''

# 基于函数构造实现多线程
import threading
import win32api
def show():
    win32api.MessageBox(0, "这是一个测试", "来自tyler", 0)

# target=show是线程函数,args=()是参数
threading.Thread(target=show, args=()).start()
threading.Thread(target=show, args=()).start()

信号限制线程数量

import threading
import time

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

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

锁定匹配数量

import threading


# 为了合理利用资源
# 凑出线程数量,也就是说一定要至少凑成两个才能执行
# 换而言之,也就是说只有创建线程数是2,或者2的倍数才能全部执行
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
这里出现Thread-3 是因为锁定在"start"之后,所以最后面Thread-3 end 是无法出现的
'''

总结:还是点多理解多看啊

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值