资讯专栏INFORMATION COLUMN

Python中过程threading.Thread的应用详细说明

89542767 / 609人阅读

  1.过程这个概念


  过程,有时候被称作轻量级进程(LightweightProcess,LWP),是程序执行流的最低控制模块。统一标准的过程由过程ID,现阶段命令表针(PC),存储器结合和局部变量构成。此外,过程是过程里的一个实体线,被系统软件多带带生产调度和分配的基本要素,过程自己并不有着服务器资源。


  2.threading.thread()简单地应用


  2.1加上过程能是程序执行迅速


  pythod的thread模块还是比较最底层的控制模块,pythod的threading模块是对thread做了很多包装,能够方便快捷被应用。


  有一点在运行时不可缺少的网络资源,但是它能与同为1个进度的其他线程共享过程所具有的所有网络资源。


</>复制代码

  1.   import threading
  2.   import time
  3.   def saySorry():
  4.   print("亲爱的,我错了,我能吃饭了吗?")
  5.   time.sleep(5)
  6.   if __name__=="__main__":
  7.   start_time1=time.time()
  8.   for i in range(5):
  9.   t=threading.Thread(target=saySorry)
  10.   t.start()#启动线程,即让线程开始执行
  11.   end_time1=time.time()
  12.   print(end_time1-start_time1)
  13.   start_time2=time.time()
  14.   for i in range(5):
  15.   t=saySorry()
  16.   end_time2=time.time()
  17.   print(end_time2-start_time2)


  输出为:


  亲爱的,我错了,我能吃饭了吗?


  亲爱的,我错了,我能吃饭了吗?


  亲爱的,我错了,我能吃饭了吗?


  亲爱的,我错了,我能吃饭了吗?


  亲爱的,我错了,我能吃饭了吗?


  0.001995086669921875


  亲爱的,我错了,我能吃饭了吗?


  亲爱的,我错了,我能吃饭了吗?


  亲爱的,我错了,我能吃饭了吗?


  亲爱的,我错了,我能吃饭了吗?


  亲爱的,我错了,我能吃饭了吗?


  25.001766204833984


  2.2主线程会等待所有的子线程结束后才结束


</>复制代码

  1.   import threading
  2.   from time import sleep,ctime
  3.   def sing():
  4.   for i in range(3):
  5.   print("正在唱歌...%d"%i)
  6.   sleep(1)
  7.   def dance():
  8.   for i in range(3):
  9.   print("正在跳舞...%d"%i)
  10.   sleep(1)
  11.   if __name__=='__main__':
  12.   print('---开始---:%s'%ctime())
  13.   t1=threading.Thread(target=sing)
  14.   t2=threading.Thread(target=dance)
  15.   t1.start()
  16.   t2.start()
  17.   #sleep(5)#屏蔽此行代码,试试看,程序是否会立马结束?
  18.   print('---结束---:%s'%ctime())


  输出为:


  ---开始---:Mon Sep 28 14:42:09 2020


  正在唱歌...0


  正在跳舞...0---结束---:Mon Sep 28 14:42:09 2020


  正在唱歌...1


  正在跳舞...1


  正在唱歌...2


  正在跳舞...2


  如果释放‘sleep(5)’,输出为:


  ---开始---:Mon Sep 28 14:43:36 2020


  正在唱歌...0


  正在跳舞...0


  正在跳舞...1


  正在唱歌...1


  正在唱歌...2正在跳舞...2


  ---结束---:Mon Sep 28 14:43:41 2020


  3.查看线程数量


</>复制代码

  1.   import threading
  2.   from time import sleep,ctime
  3.   def sing():
  4.   for i in range(3):
  5.   print("正在唱歌...%d"%i)
  6.   sleep(1)
  7.   def dance():
  8.   for i in range(3):
  9.   print("正在跳舞...%d"%i)
  10.   sleep(1)
  11.   if __name__=='__main__':
  12.   print('---开始---:%s'%ctime())
  13.   t1=threading.Thread(target=sing)
  14.   t2=threading.Thread(target=dance)
  15.   t1.start()
  16.   t2.start()
  17.   while True:
  18.   length=len(threading.enumerate())
  19.   print('当前运行的线程数为:%d'%length)
  20.   if length&lt;=1:
  21.   break
  22.   sleep(0.5)


  输出为:


  ---开始---:Mon Sep 28 14:46:16 2020


  正在唱歌...0


  正在跳舞...0


  当前运行的线程数为:3


  当前运行的线程数为:3


  正在唱歌...1


  正在跳舞...1当前运行的线程数为:3


  当前运行的线程数为:3


  正在唱歌...2


  正在跳舞...2


  当前运行的线程数为:3


  当前运行的线程数为:3


  当前运行的线程数为:1


  4.线程参数及顺序


  4.1传递参数的方法


  使用args传递参数threading.Thread(target=sing,args=(10,100,100))


  使用kwargs传递参数threading.Thread(target=sing,kwargs={“a”:10,“b”:100,“c”:100})


  同时使用args和kwargs传递参数threading.Thread(target=sing,args=(10,),kwargs={“b”:100,“c”:100})


  4.2线程的执行顺序


</>复制代码

  1.   import threading
  2.   import time
  3.   def sing():
  4.   for i in range(5):
  5.   print("我是sing")
  6.   time.sleep(1)
  7.   def dance():
  8.   for i in range(5):
  9.   print("我是dance")
  10.   time.sleep(1)
  11.   if __name__=='__main__':
  12.   #创建两个子线程
  13.   t1=threading.Thread(target=sing)
  14.   t2=threading.Thread(target=dance)
  15.   #启动子线程
  16.   t1.start()
  17.   t2.start()


  输出为:


  我是sing


  我是dance


  我是sing


  我是dance


  我是dance


  我是sing


  我是dance我是sing


  我是sing


  我是dance


  说明:


  从代码和执行结果我们可以看出,多线程程序的执行顺序是不确定的。当执行到sleep语句时,线程将被阻塞(Blocked),到sleep结束后,线程进入就绪(Runnable)状态,等待调度。而线程调度将自行选择一个线程执行。上面的代码中只能保证每个线程都运行完整个run函数,但是线程的启动顺序、run函数中每次循环的执行顺序都不能确定。


  5.守护线程


  守护线程:如果在程序中将子线程设置为守护线程,则该子线程会在主线程结束时自动退出,设置方式为thread.setDaemon(True),要在thread.start()之前设置,默认是false的,也就是主线程结束时,子线程依然在执行。


  5.1如下代码,主线程已经exit()【其实并没有真正结束】,子线程还在继续执行


</>复制代码

  1.   import threading
  2.   import time
  3.   def test():
  4.   for i in range(7):
  5.   print("test is run:",i)
  6.   time.sleep(1)
  7.   if __name__=='__main__':
  8.   #创建子线程
  9.   t1=threading.Thread(target=test)
  10.   #启动子线程
  11.   t1.start()
  12.   #休眠2秒
  13.   time.sleep(2)
  14.   print("我OVER了")
  15.   #退出
  16.   exit()


  输出为:


  test is run:0


  test is run:1


  我OVER了


  test is run:2


  test is run:3


  test is run:4


  test is run:5


  test is run:6


  5.2设置守护线程


  为线程设置守护,如果主线程结束,子线程也随之结束。


</>复制代码

  1.   import threading
  2.   import time
  3.   def test():
  4.   for i in range(7):
  5.   print("test is run:",i)
  6.   time.sleep(1)
  7.   if __name__=='__main__':
  8.   #创建子线程
  9.   t1=threading.Thread(target=test)
  10.   #设置线程保护
  11.   t1.setDaemon(True)
  12.   #启动子线程
  13.   t1.start()
  14.   #休眠2秒
  15.   time.sleep(2)
  16.   print("我OVER了")
  17.   #退出
  18.   exit()
  19.   输出为:
  20.   test is run:0
  21.   test is run:1
  22.   我OVER了
  23.   参考代码
  24.   import threading
  25.   from threading import Lock,Thread
  26.   import time,os
  27.   '''


  python多线程详解


  什么是线程?


  线程也叫轻量级进程,是操作系统能够进行运算调度的最小单位,它被包涵在进程之中,是进程中的实际运作单位。


  线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其他线程共享进程所


  拥有的全部资源。一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行


  '''


  '''


  为什么要使用多线程?


  线程在程序中是独立的、并发的执行流。与分隔的进程相比,进程中线程之间的隔离程度要小,它们共享内存、文件句柄


  和其他进程应有的状态。


  因为线程的划分尺度小于进程,使得多线程程序的并发性高。进程在执行过程之中拥有独立的内存单元,而多个线程共享


  内存,从而极大的提升了程序的运行效率。


  线程比进程具有更高的性能,这是由于同一个进程中的线程都有共性,多个线程共享一个进程的虚拟空间。线程的共享环境


  包括进程代码段、进程的共有数据等,利用这些共享的数据,线程之间很容易实现通信。


  操作系统在创建进程时,必须为改进程分配独立的内存空间,并分配大量的相关资源,但创建线程则简单得多。因此,使用多线程


  来实现并发比使用多进程的性能高得要多。


  '''


  '''


  总结起来,使用多线程编程具有如下几个优点:


  进程之间不能共享内存,但线程之间共享内存非常容易。


  操作系统在创建进程时,需要为该进程重新分配系统资源,但创建线程的代价则小得多。因此使用多线程来实现多任务并发执行比使用多进程的效率高


  python语言内置了多线程功能支持,而不是单纯地作为底层操作系统的调度方式,从而简化了python的多线程编程。


</>复制代码

  1.   '''
  2.   '''
  3.   普通创建方式
  4.   '''
  5.   #def run(n):
  6.   #print('task',n)
  7.   #time.sleep(1)
  8.   #print('2s')
  9.   #time.sleep(1)
  10.   #print('1s')
  11.   #time.sleep(1)
  12.   #print('0s')
  13.   #time.sleep(1)
  14.   #
  15.   #if __name__=='__main__':
  16.   #t1=threading.Thread(target=run,args=('t1',))#target是要执行的函数名(不是函数),args是函数对应的参数,以元组的形式存在
  17.   #t2=threading.Thread(target=run,args=('t2',))
  18.   #t1.start()
  19.   #t2.start()
  20.   '''
  21.   自定义线程:继承threading.Thread来定义线程类,其本质是重构Thread类中的run方法
  22.   '''
  23.   #class MyThread(threading.Thread):
  24.   #def __init__(self,n):
  25.   #super(MyThread,self).__init__()#重构run函数必须写
  26.   #self.n=n
  27.   #
  28.   #def run(self):
  29.   #print('task',self.n)
  30.   #time.sleep(1)
  31.   #print('2s')
  32.   #time.sleep(1)
  33.   #print('1s')
  34.   #time.sleep(1)
  35.   #print('0s')
  36.   #time.sleep(1)
  37.   #
  38.   #if __name__=='__main__':
  39.   #t1=MyThread('t1')
  40.   #t2=MyThread('t2')
  41.   #t1.start()
  42.   #t2.start()
  43.   '''


  守护线程


  下面这个例子,这里使用setDaemon(True)把所有的子线程都变成了主线程的守护线程,


  因此当主线程结束后,子线程也会随之结束,所以当主线程结束后,整个程序就退出了。


  所谓'线程守护',就是主线程不管该线程的执行情况,只要是其他子线程结束且主线程执行完毕,主线程都会关闭。也就是说:主线程不等待该守护线程的执行完再去关闭。


</>复制代码

  1.   '''
  2.   #def run(n):
  3.   #print('task',n)
  4.   #time.sleep(1)
  5.   #print('3s')
  6.   #time.sleep(1)
  7.   #print('2s')
  8.   #time.sleep(1)
  9.   #print('1s')
  10.   #
  11.   #if __name__=='__main__':
  12.   #t=threading.Thread(target=run,args=('t1',))
  13.   #t.setDaemon(True)
  14.   #t.start()
  15.   #print('end')
  16.   '''
  17.   通过执行结果可以看出,设置守护线程之后,当主线程结束时,子线程也将立即结束,不再执行
  18.   '''
  19.   '''
  20.   主线程等待子线程结束
  21.   为了让守护线程执行结束之后,主线程再结束,我们可以使用join方法,让主线程等待子线程执行
  22.   '''
  23.   #def run(n):
  24.   #print('task',n)
  25.   #time.sleep(2)
  26.   #print('5s')
  27.   #time.sleep(2)
  28.   #print('3s')
  29.   #time.sleep(2)
  30.   #print('1s')
  31.   #if __name__=='__main__':
  32.   #t=threading.Thread(target=run,args=('t1',))
  33.   #t.setDaemon(True)#把子线程设置为守护线程,必须在start()之前设置
  34.   #t.start()
  35.   #t.join()#设置主线程等待子线程结束
  36.   #print('end')
  37.   '''
  38.   多线程共享全局变量
  39.   线程时进程的执行单元,进程时系统分配资源的最小执行单位,所以在同一个进程中的多线程是共享资源的
  40.   '''
  41.   #g_num=100
  42.   #def work1():
  43.   #global g_num
  44.   #for i in range(3):
  45.   #g_num+=1
  46.   #print('in work1 g_num is:%d'%g_num)
  47.   #
  48.   #def work2():
  49.   #global g_num
  50.   #print('in work2 g_num is:%d'%g_num)
  51.   #
  52.   #if __name__=='__main__':
  53.   #t1=threading.Thread(target=work1)
  54.   #t1.start()
  55.   #time.sleep(1)
  56.   #t2=threading.Thread(target=work2)
  57.   #t2.start()
  58.   '''
  59.   由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,当多个线程同时修改同一条数据时可能会出现脏数据,
  60.   所以出现了线程锁,即同一时刻允许一个线程执行操作。线程锁用于锁定资源,可以定义多个锁,像下面的代码,当需要独占
  61.   某一个资源时,任何一个锁都可以锁定这个资源,就好比你用不同的锁都可以把这个相同的门锁住一样。
  62.   由于线程之间是进行随机调度的,如果有多个线程同时操作一个对象,如果没有很好地保护该对象,会造成程序结果的不可预期,
  63.   我们因此也称为“线程不安全”。
  64.   为了防止上面情况的发生,就出现了互斥锁(Lock
  65.   '''
  66.   #def work():
  67.   #global n
  68.   #lock.acquire()
  69.   #temp=n
  70.   #time.sleep(0.1)
  71.   #n=temp-1
  72.   #lock.release()
  73.   #
  74.   #
  75.   #if __name__=='__main__':
  76.   #lock=Lock()
  77.   #n=100
  78.   #l=[]
  79.   #for i in range(100):
  80.   #p=Thread(target=work)
  81.   #l.append(p)
  82.   #p.start()
  83.   #for p in l:
  84.   #p.join()
  85.   '''
  86.   递归锁:RLcok类的用法和Lock类一模一样,但它支持嵌套,在多个锁没有释放的时候一般会使用RLock类
  87.   '''
  88.   #def func(lock):
  89.   #global gl_num
  90.   #lock.acquire()
  91.   #gl_num+=1
  92.   #time.sleep(1)
  93.   #print(gl_num)
  94.   #lock.release()
  95.   #
  96.   #
  97.   #if __name__=='__main__':
  98.   #gl_num=0
  99.   #lock=threading.RLock()
  100.   #for i in range(10):
  101.   #t=threading.Thread(target=func,args=(lock,))
  102.   #t.start()
  103.   '''
  104.   信号量(BoundedSemaphore类)
  105.   互斥锁同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据,比如厕所有3个坑,
  106.   那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去
  107.   '''
  108.   #def run(n,semaphore):
  109.   #semaphore.acquire()#加锁
  110.   #time.sleep(3)
  111.   #print('run the thread:%sn'%n)
  112.   #semaphore.release()#释放
  113.   #
  114.   #
  115.   #if __name__=='__main__':
  116.   #num=0
  117.   #semaphore=threading.BoundedSemaphore(5)#最多允许5个线程同时运行
  118.   #for i in range(22):
  119.   #t=threading.Thread(target=run,args=('t-%s'%i,semaphore))
  120.   #t.start()
  121.   #while threading.active_count()!=1:
  122.   #pass
  123.   #else:
  124.   #print('----------all threads done-----------')
  125.   '''
  126.   python线程的事件用于主线程控制其他线程的执行,事件是一个简单的线程同步对象,其主要提供以下的几个方法:
  127.   clear将flag设置为False
  128.   set将flag设置为True
  129.   is_set判断是否设置了flag
  130.   wait会一直监听flag,如果没有检测到flag就一直处于阻塞状态
  131.   事件处理的机制:全局定义了一个Flag,当Flag的值为False,那么event.wait()就会阻塞,当flag值为True
  132.   那么event.wait()便不再阻塞
  133.   '''
  134.   event=threading.Event()
  135.   def lighter():
  136.   count=0
  137.   event.set()#初始者为绿灯
  138.   while True:
  139.   if 5&lt;count&lt;=10:
  140.   event.clear()#红灯,清除标志位
  141.   print("33[41;lmred light is on...33[0m]")
  142.   elif count&gt;10:
  143.   event.set()#绿灯,设置标志位
  144.   count=0
  145.   else:
  146.   print('33[42;lmgreen light is on...33[0m')
  147.   time.sleep(1)
  148.   count+=1
  149.   def car(name):
  150.   while True:
  151.   if event.is_set():#判断是否设置了标志位
  152.   print('[%s]running.....'%name)
  153.   time.sleep(1)
  154.   else:
  155.   print('[%s]sees red light,waiting...'%name)
  156.   event.wait()
  157.   print('[%s]green light is on,start going...'%name)
  158.   #startTime=time.time()
  159.   light=threading.Thread(target=lighter,)
  160.   light.start()
  161.   car=threading.Thread(target=car,args=('MINT',))
  162.   car.start()
  163.   endTime=time.time()
  164.   #print('用时:',endTime-startTime)
  165.   '''


  GIL全局解释器


  在非python环境中,单核情况下,同时只能有一个任务执行。多核时可以支持多个线程同时执行。但是在python中,无论有多少个核


  同时只能执行一个线程。究其原因,这就是由于GIL的存在导致的。


  GIL的全程是全局解释器,来源是python设计之初的考虑,为了数据安全所做的决定。某个线程想要执行,必须先拿到GIL,我们可以


  把GIL看做是“通行证”,并且在一个python进程之中,GIL只有一个。拿不到线程的通行证,并且在一个python进程中,GIL只有一个,


  拿不到通行证的线程,就不允许进入CPU执行。GIL只在cpython中才有,因为cpython调用的是c语言的原生线程,所以他不能直接操


  作cpu,而只能利用GIL保证同一时间只能有一个线程拿到数据。而在pypy和jpython中是没有GIL的


  python在使用多线程的时候,调用的是c语言的原生过程。


  '''


  '''


  python针对不同类型的代码执行效率也是不同的


  1、CPU密集型代码(各种循环处理、计算等),在这种情况下,由于计算工作多,ticks技术很快就会达到阀值,然后出发GIL的


  释放与再竞争(多个线程来回切换当然是需要消耗资源的),所以python下的多线程对CPU密集型代码并不友好。


  2、IO密集型代码(文件处理、网络爬虫等设计文件读写操作),多线程能够有效提升效率(单线程下有IO操作会进行IO等待,


  造成不必要的时间浪费,而开启多线程能在线程A等待时,自动切换到线程B,可以不浪费CPU的资源,从而能提升程序的执行


  效率)。所以python的多线程对IO密集型代码比较友好。


  '''


  '''


  主要要看任务的类型,我们把任务分为I/O密集型和计算密集型,而多线程在切换中又分为I/O切换和时间切换。如果任务属于是I/O密集型,


  若不采用多线程,我们在进行I/O操作时,势必要等待前面一个I/O任务完成后面的I/O任务才能进行,在这个等待的过程中,CPU处于等待


  状态,这时如果采用多线程的话,刚好可以切换到进行另一个I/O任务。这样就刚好可以充分利用CPU避免CPU处于闲置状态,提高效率。但是


  如果多线程任务都是计算型,CPU会一直在进行工作,直到一定的时间后采取多线程时间切换的方式进行切换线程,此时CPU一直处于工作状态,


  此种情况下并不能提高性能,相反在切换多线程任务时,可能还会造成时间和资源的浪费,导致效能下降。这就是造成上面两种多线程结果不能的解释。


  结论:I/O密集型任务,建议采取多线程,还可以采用多进程+协程的方式(例如:爬虫多采用多线程处理爬取的数据);对于计算密集型任务,python此时就不适用了。


  '''


  综上所述,这篇文章就给大家介绍到这里了,希望可以给大家带来帮助。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/128697.html

相关文章

  • Python迅速从短视频获取视频帧办法详细说明

      本文给大家介绍一类从视频里获取视频帧的办法,因为单核获取视频帧速率比较慢,因而接下来我们增强了线程同步的办法,感兴趣的朋友能够出手试一试  Python迅速获取视频帧(线程同步)  现在详细介绍一下一类从视频里获取视频帧的办法,因为单核获取视频帧速率比较慢,因而接下来我们增强了线程同步的办法。  1、获取视频帧  获取视频帧关键用了Opencv控制模块。  在其中:  camera=cv2.V...

    89542767 评论0 收藏0
  • PyTips 0x 12 - Python 线程与协程(1)

    摘要:中关于线程的标准库是,之前在版本中的在之后更名为,无论是还是都应该尽量避免使用较为底层的而应该使用。而与线程相比,协程尤其是结合事件循环无论在编程模型还是语法上,看起来都是非常友好的单线程同步过程。 项目地址:https://git.io/pytips 要说到线程(Thread)与协程(Coroutine)似乎总是需要从并行(Parallelism)与并发(Concurrency)谈起...

    el09xccxy 评论0 收藏0
  • 浅谈Python多线程

    摘要:进程可创建多个线程来执行同一程序的不同部分。就绪等待线程调度。运行线程正常运行阻塞暂停运行,解除阻塞后进入状态重新等待调度。消亡线程方法执行完毕返回或者异常终止。多线程多的情况下,依次执行各线程的方法,前头一个结束了才能执行后面一个。 浅谈Python多线程 作者简介: 姓名:黄志成(小黄)博客: 博客 线程 一.什么是线程? 操作系统原理相关的书,基本都会提到一句很经典的话: 进程...

    zsirfs 评论0 收藏0
  • Python多线程

    摘要:多线程的理解多进程和多线程都可以执行多个任务,线程是进程的一部分。多线程创建在中,同样可以实现多线程,有两个标准模块和,不过我们主要使用更高级的模块。多线程的应用场景。 1、多线程的理解 多进程和多线程都可以执行多个任务,线程是进程的一部分。线程的特点是线程之间可以共享内存和变量,资源消耗少(不过在Unix环境中,多进程和多线程资源调度消耗差距不明显,Unix调度较快),缺点是线程之间...

    dcr309duan 评论0 收藏0
  • # Python 多线程和锁

    摘要:多线程和锁作者博客进程和线程进程是执行中的计算机程序。线程包括开始执行顺序和结束三部分。的多进程相关模块模块是高级别的多线程模块。线程锁当多线程争夺锁时,允许第一个获得锁的线程进入临街区,并执行代码。 Python 多线程和锁 作者博客:http://zzir.cn/ 进程和线程 进程是执行中的计算机程序。每个进程都拥有自己的地址空间、内存、数据栈及其它的辅助数据。操作系统管理着所有的...

    cpupro 评论0 收藏0

发表评论

0条评论

89542767

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<