搜索
首页后端开发Python教程一篇文章带你全面解析不一样的线程


前言

在将今天的知识点之前,大家是否了解线程,进程和协程了,那我们先来初步了解下吧。


线程

中央处理器的调度单元,简单点说就是程序中的末端执行者,相当于小弟的位置。

有人说python中的线程是个鸡肋,这是因为有了GIL,但是又不是一味的鸡肋,毕竟在执行io操作时还是挺管用的,只是在执行计算时就显得不尽人意。下面我们来看下线程的具体使用方法:

1.导入线程模块:

import threading as t

2.线程的用法

tt=t.Thread(group=None,target=None,name=None,args=(),kwargs={},name='',daemon=None)
group:线程组,必须是None
target:运行的函数
args:传入函数的参数元组
kwargs:传入函数的参数字典
name:线程名
daemon:线程是否随主线程退出而退出(守护线程)


Thread方法的返回值还有以下方法:
tt.start() : 激活线程,
tt.getName() : 获取线程的名称
tt.setName() :设置线程的名称 
tt.name : 获取或设置线程的名称
tt.is_alive() :判断线程是否为激活状态
tt.isAlive() :判断线程是否为激活状态
tt.setDaemon() 设置为守护线程(默认:False)
tt.isDaemon() :判断是否为守护线程
tt.ident :获取线程的标识符。只有在调用了start()方法之后该属性才有效
tt.join() :逐个执行每个线程,执行完毕后继续往下执行
tt.run() :自动执行线程对象


t的方法也有:
t.active_count(): 返回正在运行线程的数量
t.enumerate(): 返回正在运行线程的列表
t.current_thread().getName() 获取当前线程的名字
t.TIMEOUT_MAX 设置t的全局超时时间

下面我们来看下吧:

一篇文章带你全面解析不一样的线程


3.创建线程

线程可以使用Thread方法创建,也可以重写线程类的run方法实现,线程可分为单线程和多线程。

3.1 使用Thread方法来创建:

3.1.1 单线程
def xc():
    for y in range(100):
        print('运行中'+str(y))
tt=t.Thread(target=xc,args=()) #方法加入到线程
tt.start()  #开始线程
tt.join() #等待子线程结束
3.1.2 多线程
def xc(num):
    print('运行:'+str(num))
c=[]
for y in range(100):
    tt=t.Thread(target=xc,args=(y,))
    tt.start() #开始线程
    c.append(tt) #创建列表并添加线程
for x in c:
    x.join()  #等待子线程结束

3.2 重写线程的类方法

3.2.1 单线程
class Xc(t.Thread): #继承Thread类
    def __init__(self):
        super(Xc, self).__init__() 
    def run(self):  #重写run方法
        for y in range(100):
            print('运行中'+str(y))
x=Xc() 
x.start() #开始线程
x.join()  #等待子线程结束


也可以这么写:
Xc().run() 和上面的效果是一样的
3.2.2 多线程
class Xc(t.Thread): #继承Thread类
    def __init__(self):
        super(Xc, self).__init__() 
    def run(self,num):  #重写run方法
        print('运行:'+str(num))
x=Xc()
for y in range(10):
    x.run(y) #运行

4.线程锁

为什么要加锁,看了这个你就知道了:

一篇文章带你全面解析不一样的线程

多线程在运行时同时访问一个对象会产生抢占资源的情况,所以我们必须得束缚它,所以就要给他加一把锁把他锁住,这就是同步锁。要了解锁,我们得先创建锁,线程中有两种锁:Lock和RLock。

4.1 Lock

使用方法:

# 获取锁
当获取不到锁时,默认进入阻塞状态,设置超时时间,直到获取到锁,后才继续。非阻塞时,timeout禁止设置。如果超时依旧未获取到锁,返回False。
Lock.acquire(blocking=True,timeout=1)   


#释放锁,已上锁的锁,会被设置为unlocked。如果未上锁调用,会抛出RuntimeError异常。
Lock.release()

互斥锁,同步数据,解决多线程的安全问题:

n=10
lock=t.Lock()
def xc(num):
    lock.acquire()
    print('运行+:'+str(num+n))
    print('运行-:'+str(num-n))
    lock.release()
c=[]
for y in range(10):
    tt=t.Thread(target=xc,args=(y,))
    tt.start()
    c.append(tt)
for x in c:
    x.join()

这样就显得有条理了,而且输出也是先+后-。Lock在一个线程中多次使用同一资源会造成死锁。

死锁问题:

n=10
lock1=t.Lock()
lock2=t.Lock()
def xc(num):
  lock1.acquire()
  print('运行+:'+str(num+n))
  lock2.acquire()
  print('运行-:'+str(num-n))
  lock2.release()
  lock1.release()
c=[]
for y in range(10):
  tt=t.Thread(target=xc,args=(y,))
  tt.start()
  c.append(tt)
for x in c:
  x.join()


4.2 RLock

相比Lock它可以递归,支持在同一线程中多次请求同一资源,并允许在同一线程中被多次锁定,但是acquire和release必须成对出现。

使用递归锁来解决死锁:

n=10
lock1=t.RLock()
lock2=t.RLock()
def xc(num):
  lock1.acquire()
  print('运行+:'+str(num+n))
  lock2.acquire()
  print('运行-:'+str(num-n))
  lock2.release()
  lock1.release()
c=[]
for y in range(10):
  tt=t.Thread(target=xc,args=(y,))
  tt.start()
  c.append(tt)
for x in c:
  x.join()

这时候,输出变量就变得仅仅有条了,不在随意抢占资源。关于线程锁,还可以使用with更加方便:

#with上下文管理,锁对象支持上下文管理
with lock:   #with表示自动打开自动释放锁
  for i in range(10): #锁定期间,其他人不可以干活
    print(i)
  #上面的和下面的是等价的
if lock.acquire(1):#锁住成功继续干活,没有锁住成功就一直等待,1代表独占
  for i in range(10): #锁定期间,其他线程不可以干活
    print(i)
  lock.release() #释放锁


4.3 条件锁

等待通过,Condition(lock=None),可以传入lock或者Rlock,默认Rlock,使用方法:

Condition.acquire(*args)      获取锁


Condition.wait(timeout=None)  等待通知,timeout设置超时时间


Condition.notify(num)唤醒至多指定数目个数的等待的线程,没有等待的线程就没有任何操作


Condition.notify_all()  唤醒所有等待的线程 或者notifyAll()
def ww(c):
  with c:
    print('init')
    c.wait(timeout=5) #设置等待超时时间5
    print('end')
def xx(c):
  with c:
    print('nono')
    c.notifyAll() #唤醒所有线程
    print('start')
    c.notify(1) #唤醒一个线程
    print('21')
c=t.Condition() #创建条件
t.Thread(target=ww,args=(c,)).start()
t.Thread(target=xx,args=(c,)).start()

这样就可以在等待的时候唤醒函数里唤醒其他函数里所存在的其他线程了。


5.信号量

信号量可以分为有界信号量和无解信号量,下面我们来具体看看他们的用法:

5.1 有界信号量

它不允许使用release超出初始值的范围,否则,抛出ValueError异常。

#构造方法。value为初始信号量。value小于0,抛出ValueError异常
b=t.BoundedSemaphore(value=1)  


#获取信号量时,计数器减1,即_value的值减少1。如果_value的值为0会变成阻塞状态。获取成功返回True
BoundedSemaphore.acquire(blocking=True,timeout=None)  


#释放信号量,计数器加1。即_value的值加1,超过初始化值会抛出异常ValueError。
BoundedSemaphore.release()  


#信号量,当前信号量
BoundedSemaphore._value

一篇文章带你全面解析不一样的线程

可以看到了多了个release后报错了。


5.2 无界信号量

它不检查release的上限情况,只是单纯的加减计数器。

一篇文章带你全面解析不一样的线程

可以看到虽然多了个release,但是没有问题,而且信号量的数量不受限制。


6.Event

线程间通信,通过线程设置的信号标志(flag)的False 还是True来进行操作,常见方法有:

event.set()      flag设置为True
event.clear()  flag设置为False
event.is_set()  flag是否为True,如果 event.isSet()==False将阻塞线程;
设置等待flag为True的时长,None为无限等待。等到返回True,未等到超时则返回False
event.wait(timeout=None)

下面通过一个例子具体讲述:

import time
e=t.Event()
def ff(num):
  while True:
    if num<5:
      e.clear()   #清空信号标志
      print(&#39;清空&#39;)
    if num>=5:
      e.wait(timeout=1) #等待信号标志为真
      e.set()
      print(&#39;启动&#39;)
      if e.isSet(): #如果信号标志为真则清除标志
        e.clear()
        print(&#39;停止&#39;)
    if num==10:
      e.wait(timeout=3)
      e.clear()
      print(&#39;退出&#39;)
      break
    num+=1
    time.sleep(2)
ff(1)

一篇文章带你全面解析不一样的线程

设置延迟后可以看到效果相当明显,我们让他干什么事他就干什么事。


7.local

可以为各个线程创建完全属于它们自己的变量(线程局部变量),而且它们的值都在当前调用它的线程当中,以字典的形式存在。下面我们来看下:

l=t.local()  #创建一个线程局部变量
def ff(num):
  l.x=100  #设置l变量的x方法的值为100
  for y in range(num):
    l.x+=3 #改变值
  print(str(l.x))


for y in range(10):
  t.Thread(target=ff,args=(y,)).start() #开始执行线程

那么,可以将变量的x方法设为全局变量吗?我们来看下:

一篇文章带你全面解析不一样的线程

可以看出他报错了,产生错误的原因是因为这个类中没有属性x,我们可以简单的理解为局部变量就只接受局部。


8.Timer

设置定时计划,可以在规定的时间内反复执行某个方法。他的使用方法是:

t.Timer(num,func,*args,**kwargs) #在指定时间内再次重启程序

下面我们来看下:

def f():
  print(&#39;start&#39;)
  global t #防止造成线程堆积导致最终程序退出
  tt= t.Timer(3, f)
  tt.start()
f()

这样就达到了每三秒执行一次f函数的效果。


总结

通过对线程的全面解析我们了解到了线程的重要性,它可以将我们复杂的问题变得简单化,对于喜欢玩爬虫的小伙伴们可以说是相当有用了,本文基本覆盖了线程的所有概念,希望能帮到大家。

以上是一篇文章带你全面解析不一样的线程的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文转载于:Python当打之年。如有侵权,请联系admin@php.cn删除
Python和时间:充分利用您的学习时间Python和时间:充分利用您的学习时间Apr 14, 2025 am 12:02 AM

要在有限的时间内最大化学习Python的效率,可以使用Python的datetime、time和schedule模块。1.datetime模块用于记录和规划学习时间。2.time模块帮助设置学习和休息时间。3.schedule模块自动化安排每周学习任务。

Python:游戏,Guis等Python:游戏,Guis等Apr 13, 2025 am 12:14 AM

Python在游戏和GUI开发中表现出色。1)游戏开发使用Pygame,提供绘图、音频等功能,适合创建2D游戏。2)GUI开发可选择Tkinter或PyQt,Tkinter简单易用,PyQt功能丰富,适合专业开发。

Python vs.C:申请和用例Python vs.C:申请和用例Apr 12, 2025 am 12:01 AM

Python适合数据科学、Web开发和自动化任务,而C 适用于系统编程、游戏开发和嵌入式系统。 Python以简洁和强大的生态系统着称,C 则以高性能和底层控制能力闻名。

2小时的Python计划:一种现实的方法2小时的Python计划:一种现实的方法Apr 11, 2025 am 12:04 AM

2小时内可以学会Python的基本编程概念和技能。1.学习变量和数据类型,2.掌握控制流(条件语句和循环),3.理解函数的定义和使用,4.通过简单示例和代码片段快速上手Python编程。

Python:探索其主要应用程序Python:探索其主要应用程序Apr 10, 2025 am 09:41 AM

Python在web开发、数据科学、机器学习、自动化和脚本编写等领域有广泛应用。1)在web开发中,Django和Flask框架简化了开发过程。2)数据科学和机器学习领域,NumPy、Pandas、Scikit-learn和TensorFlow库提供了强大支持。3)自动化和脚本编写方面,Python适用于自动化测试和系统管理等任务。

您可以在2小时内学到多少python?您可以在2小时内学到多少python?Apr 09, 2025 pm 04:33 PM

两小时内可以学到Python的基础知识。1.学习变量和数据类型,2.掌握控制结构如if语句和循环,3.了解函数的定义和使用。这些将帮助你开始编写简单的Python程序。

如何在10小时内通过项目和问题驱动的方式教计算机小白编程基础?如何在10小时内通过项目和问题驱动的方式教计算机小白编程基础?Apr 02, 2025 am 07:18 AM

如何在10小时内教计算机小白编程基础?如果你只有10个小时来教计算机小白一些编程知识,你会选择教些什么�...

如何在使用 Fiddler Everywhere 进行中间人读取时避免被浏览器检测到?如何在使用 Fiddler Everywhere 进行中间人读取时避免被浏览器检测到?Apr 02, 2025 am 07:15 AM

使用FiddlerEverywhere进行中间人读取时如何避免被检测到当你使用FiddlerEverywhere...

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
4 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
4 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
4 周前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
1 个月前By尊渡假赌尊渡假赌尊渡假赌

热工具

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

功能强大的PHP集成开发环境

VSCode Windows 64位 下载

VSCode Windows 64位 下载

微软推出的免费、功能强大的一款IDE编辑器

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具