python多线程超详细详解

python中的多线程是一个非常重要的知识点,今天为大家对多线程进行详细的说明,代码中的注释有多线程的知识点还有测试用的实例。

import threading
from threading import Lock,Thread
import time,os

'''
          python多线程详解
  什么是线程?
  线程也叫轻量级进程,是操作系统能够进行运算调度的最小单位,它被包涵在进程之中,是进程中的实际运作单位。
  线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其他线程共享进程所
  拥有的全部资源。一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行
'''

'''
 为什么要使用多线程?
 线程在程序中是独立的、并发的执行流。与分隔的进程相比,进程中线程之间的隔离程度要小,它们共享内存、文件句柄
 和其他进程应有的状态。
 因为线程的划分尺度小于进程,使得多线程程序的并发性高。进程在执行过程之中拥有独立的内存单元,而多个线程共享
 内存,从而极大的提升了程序的运行效率。
 线程比进程具有更高的性能,这是由于同一个进程中的线程都有共性,多个线程共享一个进程的虚拟空间。线程的共享环境
 包括进程代码段、进程的共有数据等,利用这些共享的数据,线程之间很容易实现通信。
 操作系统在创建进程时,必须为改进程分配独立的内存空间,并分配大量的相关资源,但创建线程则简单得多。因此,使用多线程
 来实现并发比使用多进程的性能高得要多。
'''

'''
 总结起来,使用多线程编程具有如下几个优点:
 进程之间不能共享内存,但线程之间共享内存非常容易。
 操作系统在创建进程时,需要为该进程重新分配系统资源,但创建线程的代价则小得多。因此使用多线程来实现多任务并发执行比使用多进程的效率高
 python语言内置了多线程功能支持,而不是单纯地作为底层操作系统的调度方式,从而简化了python的多线程编程。
'''

'''
 普通创建方式
'''
# def run(n):
#  print('task',n)
#  time.sleep(1)
#  print('2s')
#  time.sleep(1)
#  print('1s')
#  time.sleep(1)
#  print('0s')
#  time.sleep(1)
#
# if __name__ == '__main__':
#  t1 = threading.Thread(target=run,args=('t1',))  # target是要执行的函数名(不是函数),args是函数对应的参数,以元组的形式存在
#  t2 = threading.Thread(target=run,args=('t2',))
#  t1.start()
#  t2.start()

'''
 自定义线程:继承threading.Thread来定义线程类,其本质是重构Thread类中的run方法
'''
# class MyThread(threading.Thread):
#  def __init__(self,n):
#   super(MyThread,self).__init__() #重构run函数必须写
#   self.n = n
#
#  def run(self):
#   print('task',self.n)
#   time.sleep(1)
#   print('2s')
#   time.sleep(1)
#   print('1s')
#   time.sleep(1)
#   print('0s')
#   time.sleep(1)
#
# if __name__ == '__main__':
#  t1 = MyThread('t1')
#  t2 = MyThread('t2')
#  t1.start()
#  t2.start()

'''
 守护线程
 下面这个例子,这里使用setDaemon(True)把所有的子线程都变成了主线程的守护线程,
 因此当主线程结束后,子线程也会随之结束,所以当主线程结束后,整个程序就退出了。
 所谓'线程守护',就是主线程不管该线程的执行情况,只要是其他子线程结束且主线程执行完毕,主线程都会关闭。也就是说:主线程不等待该守护线程的执行完再去关闭。
'''
# def run(n):
#  print('task',n)
#  time.sleep(1)
#  print('3s')
#  time.sleep(1)
#  print('2s')
#  time.sleep(1)
#  print('1s')
#
# if __name__ == '__main__':
#  t=threading.Thread(target=run,args=('t1',))
#  t.setDaemon(True)
#  t.start()
#  print('end')
'''
 通过执行结果可以看出,设置守护线程之后,当主线程结束时,子线程也将立即结束,不再执行
'''

'''
 主线程等待子线程结束
 为了让守护线程执行结束之后,主线程再结束,我们可以使用join方法,让主线程等待子线程执行
'''
# def run(n):
#  print('task',n)
#  time.sleep(2)
#  print('5s')
#  time.sleep(2)
#  print('3s')
#  time.sleep(2)
#  print('1s')
# if __name__ == '__main__':
#  t=threading.Thread(target=run,args=('t1',))
#  t.setDaemon(True) #把子线程设置为守护线程,必须在start()之前设置
#  t.start()
#  t.join()  #设置主线程等待子线程结束
#  print('end')

'''
 多线程共享全局变量
 线程时进程的执行单元,进程时系统分配资源的最小执行单位,所以在同一个进程中的多线程是共享资源的
'''
# g_num = 100
# def work1():
#  global g_num
#  for i in range(3):
#   g_num+=1
#  print('in work1 g_num is : %d' % g_num)
#
# def work2():
#  global g_num
#  print('in work2 g_num is : %d' % g_num)
#
# if __name__ == '__main__':
#  t1 = threading.Thread(target=work1)
#  t1.start()
#  time.sleep(1)
#  t2=threading.Thread(target=work2)
#  t2.start()

'''
  由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,当多个线程同时修改同一条数据时可能会出现脏数据,
 所以出现了线程锁,即同一时刻允许一个线程执行操作。线程锁用于锁定资源,可以定义多个锁,像下面的代码,当需要独占
 某一个资源时,任何一个锁都可以锁定这个资源,就好比你用不同的锁都可以把这个相同的门锁住一样。
  由于线程之间是进行随机调度的,如果有多个线程同时操作一个对象,如果没有很好地保护该对象,会造成程序结果的不可预期,
 我们因此也称为“线程不安全”。
  为了防止上面情况的发生,就出现了互斥锁(Lock)
'''
# def work():
#  global n
#  lock.acquire()
#  temp = n
#  time.sleep(0.1)
#  n = temp-1
#  lock.release()
#
#
# if __name__ == '__main__':
#  lock = Lock()
#  n = 100
#  l = []
#  for i in range(100):
#   p = Thread(target=work)
#   l.append(p)
#   p.start()
#  for p in l:
#   p.join()

'''
 递归锁:RLcok类的用法和Lock类一模一样,但它支持嵌套,在多个锁没有释放的时候一般会使用RLock类
'''
# def func(lock):
#  global gl_num
#  lock.acquire()
#  gl_num += 1
#  time.sleep(1)
#  print(gl_num)
#  lock.release()
#
#
# if __name__ == '__main__':
#  gl_num = 0
#  lock = threading.RLock()
#  for i in range(10):
#   t = threading.Thread(target=func,args=(lock,))
#   t.start()

'''
 信号量(BoundedSemaphore类)
 互斥锁同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据,比如厕所有3个坑,
 那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去
'''
# def run(n,semaphore):
#  semaphore.acquire() #加锁
#  time.sleep(3)
#  print('run the thread:%s\n' % n)
#  semaphore.release() #释放
#
#
# if __name__== '__main__':
#  num=0
#  semaphore = threading.BoundedSemaphore(5) #最多允许5个线程同时运行
#  for i in range(22):
#   t = threading.Thread(target=run,args=('t-%s' % i,semaphore))
#   t.start()
#  while threading.active_count() !=1:
#   pass
#  else:
#   print('----------all threads done-----------')

'''
 python线程的事件用于主线程控制其他线程的执行,事件是一个简单的线程同步对象,其主要提供以下的几个方法:
  clear将flag设置为 False
  set将flag设置为 True
  is_set判断是否设置了flag
  wait会一直监听flag,如果没有检测到flag就一直处于阻塞状态
 事件处理的机制:全局定义了一个Flag,当Flag的值为False,那么event.wait()就会阻塞,当flag值为True,
 那么event.wait()便不再阻塞
'''
event = threading.Event()
def lighter():
 count = 0
 event.set()   #初始者为绿灯
 while True:
  if 5 < count <=10:
   event.clear() #红灯,清除标志位
   print("\33[41;lmred light is on...\033[0m]")
  elif count > 10:
   event.set() #绿灯,设置标志位
   count = 0
  else:
   print('\33[42;lmgreen light is on...\033[0m')

  time.sleep(1)
  count += 1

def car(name):
 while True:
  if event.is_set():  #判断是否设置了标志位
   print('[%s] running.....'%name)
   time.sleep(1)
  else:
   print('[%s] sees red light,waiting...'%name)
   event.wait()
   print('[%s] green light is on,start going...'%name)

# startTime = time.time()
light = threading.Thread(target=lighter,)
light.start()

car = threading.Thread(target=car,args=('MINT',))
car.start()
endTime = time.time()
# print('用时:',endTime-startTime)

'''
       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此时就不适用了。
'''

到此这篇关于python多线程超详细详解的文章就介绍到这了,更多相关python多线程内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • python基于concurrent模块实现多线程

    引言 之前也写过多线程的博客,用的是 threading ,今天来讲下 python 的另外一个自带库 concurrent .concurrent 是在 Python3.2 中引入的,只用几行代码就可以编写出线程池/进程池,并且计算型任务效率和 mutiprocessing.pool 提供的 poll 和 ThreadPoll 相比不分伯仲,而且在 IO 型任务由于引入了 Future 的概念效率要高数倍.而 threading 的话还要自己维护相关的队列防止死锁,代码的可读性也会下降,相反

  • python 实现多线程的三种方法总结

    1._thread.start_new_thread(了解) import threading import time import _thread def job(): print("这是一个需要执行的任务.....") print("当前线程的个数:", threading.active_count() ) print("当前线程的信息:", threading.current_thread()) time.sleep(100) if __n

  • 深入理解python多线程编程

    进程 进程的概念: 进程是资源分配的最小单位,他是操作系统进行资源分配和调度运行的基本单位.通俗理解:一个正在运行的一个程序就是一个进程.例如:正在运行的qq.wechat等,它们都是一个进程. 进程的创建步骤 1.导入进程包  import multiprocessing 2.通过进程类创建进程对象  进程对象 = multiprocessing.Process() 3.启动进程执行任务  进程对象.start() import multiprocessing import time def

  • Python 多线程之threading 模块的使用

    简介 Python 通过 _thread 和 threading 模块提供了对多线程的支持,threading 模块兼具了 _thread 模块的现有功能,又扩展了一些新的功能,具有十分丰富的线程操作功能 创建线程 使用 threading 模块创建线程通常有两种方式: 1)使用 threading 模块中 Thread 类的构造器创建线程,即直接对类 threading.Thread 进行实例化,并调用实例化对象的 start 方法创建线程: 2)继承 threading 模块中的 Threa

  • python 多进程和多线程使用详解

    进程和线程 进程是系统进行资源分配的最小单位,线程是系统进行调度执行的最小单位: 一个应用程序至少包含一个进程,一个进程至少包含一个线程: 每个进程在执行过程中拥有独立的内存空间,而一个进程中的线程之间是共享该进程的内存空间的: 计算机的核心是CPU,它承担了所有的计算任务.它就像一座工厂,时刻在运行. 假定工厂的电力有限,一次只能供给一个车间使用.也就是说,一个车间开工的时候,其他车间都必须停工.背后的含义就是,单个CPU一次只能运行一个任务.编者注: 多核的CPU就像有了多个发电厂,使多工厂

  • Python之多进程与多线程的使用

    进程与线程 想象在学校的一个机房,有固定数量的电脑,老师安排了一个爬虫任务让大家一起完成,每个学生使用一台电脑爬取部分数据,将数据放到一个公共数据库.共同资源就像公共数据库,进程就像每一个学生,每多一个学生,就多一个进程来完成这个任务,机房里的电脑数量就像CPU,所以进程数量是CPU决定的,线程就像学生用一台电脑开多个爬虫,爬虫数量由每台电脑的运行内存决定. 一个CPU可以有多个进程,一个进程有一个或多个线程. 多进程 1.导包 from multiprocessing import Proce

  • Python多进程与多线程的使用场景详解

    前言 Python多进程适用的场景:计算密集型(CPU密集型)任务 Python多线程适用的场景:IO密集型任务 计算密集型任务一般指需要做大量的逻辑运算,比如上亿次的加减乘除,使用多核CPU可以并发提高计算性能. IO密集型任务一般指输入输出型,比如文件的读取,或者网络的请求,这类场景一般会遇到IO阻塞,使用多核CPU来执行并不会有太高的性能提升. 下面使用一台64核的虚拟机来执行任务,通过示例代码来区别它们, 示例1:执行计算密集型任务,进行1亿次运算 使用多进程 from multipro

  • python 如何用map()函数创建多线程任务

    对于多线程的使用,我们经常是用thread来创建,比较繁琐. 在Python中,可以使用map函数简化代码.map可以实现多任务的并发 简单说明map()实现多线程原理: task = ['任务1', '任务2', '任务3', -] map 函数一手包办了序列操作.参数传递和结果保存等一系列的操作,map函数负责将线程分给不同的CPU. 在 Python 中有个两个库包含了 map 函数: multiprocessing 和它鲜为人知的子库 multiprocessing.dummy.dumm

  • python 多线程爬取壁纸网站的示例

    基本开发环境 · Python 3.6 · Pycharm 需要导入的库 目标网页分析 网站是静态网站,没有加密,可以直接爬取 整体思路: 1.先在列表页面获取每张壁纸的详情页地址 2.在壁纸详情页面获取壁纸真实高清url地址 3.保存地址 代码实现 模拟浏览器请请求网页,获取网页数据 这里只选择爬取前10页的数据 代码如下 import threading import parsel import requests def get_html(html_url): ''' 获取网页源代码 :pa

  • python多线程超详细详解

    python中的多线程是一个非常重要的知识点,今天为大家对多线程进行详细的说明,代码中的注释有多线程的知识点还有测试用的实例. import threading from threading import Lock,Thread import time,os ''' python多线程详解 什么是线程? 线程也叫轻量级进程,是操作系统能够进行运算调度的最小单位,它被包涵在进程之中,是进程中的实际运作单位. 线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其他线程

  • Python 多线程的实例详解

     Python 多线程的实例详解 一)线程基础 1.创建线程: thread模块提供了start_new_thread函数,用以创建线程.start_new_thread函数成功创建后还可以对其进行操作. 其函数原型: start_new_thread(function,atgs[,kwargs]) 其参数含义如下: function: 在线程中执行的函数名     args:元组形式的参数列表.     kwargs: 可选参数,以字典的形式指定参数 方法一:通过使用thread模块中的函数创

  • Python 多线程超详细到位总结

    目录 多线程threading 线程池 线程互斥 lock与Rlock的区别 在实际处理数据时,因系统内存有限,我们不可能一次把所有数据都导出进行操作,所以需要批量导出依次操作.为了加快运行,我们会采用多线程的方法进行数据处理,以下为我总结的多线程批量处理数据的模板: import threading # 从数据库提取数据的类 class Scheduler(): def __init__(self): self._lock = threading.RLock() self.start = 0

  • python多线程用法实例详解

    本文实例分析了python多线程用法.分享给大家供大家参考.具体如下: 今天在学习尝试学习python多线程的时候,突然发现自己一直对super的用法不是很清楚,所以先总结一些遇到的问题.当我尝试编写下面的代码的时候: 复制代码 代码如下: class A():     def __init__( self ):         print "A" class B( A ):     def __init__( self ):         super( B, self ).__in

  • Python字符串str超详细详解(适合新手!)

    目录 1.创建字符串 1.1 使用 ’ ’ 或 " " 创建字符串 1.2 使用 str()函数 转换为字符串 2.访问字符串 2.1 下标索引访问 2.2 切片访问 2.3 for循环遍历字符串 2.4 检查元素是否存在 3.字符串基础知识 3.1 字符串更新 3.2 字符串连接(合并)/复制(重复) 3.3 转义字符 3.4 打印原始字符 r / R 3.5 格式字符串 3.6 三引号 3.7 f-string 3.8 Unicode 字符串 4.内置函数 4.1 打印输出 pri

  • Python多线程编程入门详解

    目录 一.任务.进程和线程 任务 进程 线程 进程和线程的关系 二.Python既支持多进程,又支持多线程 Python实现多进程 Process进程类的说明 Python实现多线程 线程类Thread 总结 一.任务.进程和线程 现代操作系统比如Mac OS X, Linux,Windows等,都是支持"多任务"的操作系统. 什么叫"多任务"(multitasking)呢?简单地说,就是操作系统可以同时运行多个任务.例如你一边在用浏览器上查资料,一边在听MP3,一

  • python爬虫中多线程的使用详解

    queue介绍 queue是python的标准库,俗称队列.可以直接import引用,在python2.x中,模块名为Queue.python3直接queue即可 在python中,多个线程之间的数据是共享的,多个线程进行数据交换的时候,不能够保证数据的安全性和一致性,所以当多个线程需要进行数据交换的时候,队列就出现了,队列可以完美解决线程间的数据交换,保证线程间数据的安全性和一致性. #多线程实战栗子(糗百) #用一个队列Queue对象, #先产生所有url,put进队列: #开启多线程,把q

  • Python基础之进程详解

    一.前言 进程,一个新鲜的字眼,可能有些人并不了解,它是系统某个运行程序的载体,这个程序可以有单个或者多个进程,一般来说,进程是通过系统CPU 内核数来分配并设置的,我们可以来看下系统中的进程: 可以看到,360浏览器是真的皮,这么多进程啊,当然可以这样来十分清楚的看进程线程使用情况: 通过任务管理器中的资源监视器,是不是很厉害了,哈哈哈.讲完了这些,再说说用法. 二.基本用法 进程能干什么,这是我们要深思熟虑的事情.我们都知道一个程序运行会创建进程,所以程序在创建这些进程的时候,为了让它们更能

  • Python matplotlib 绘制散点图详解建议收藏

    目录 前言 1. 散点图概述 什么是散点图? 散点图使用场景 绘制散点图步骤 案例展示  2. 散点图属性 设置散点大小 设置散点颜色 设置散点样式 设置透明度 设置散点边框 3. 添加折线散点图 4. 多类型散点图 5. 颜色条散点图 6. 曲线散点图 总结 前言 我们在matplotlib模块学习中,发现有常用的反映数据变化的折线图,对比数据类型差异的柱状图和反应数据频率分布情况的直方图. 往期内容速看 Python用 matplotlib 绘制柱状图 Python matplotlib底层

  • Tensorflow2.4使用Tuner选择模型最佳超参详解

    目录 前言 实现过程 1. 获取 MNIST 数据并进行处理 2. 搭建超模型 3. 实例化调节器并进行模型超调 4. 训练模型获得最佳 epoch 5. 使用最有超参数集进行模型训练和评估 前言 本文使用 cpu 版本的 tensorflow 2.4 ,选用 Keras Tuner 工具以 Fashion 数据集的分类任务为例,完成最优超参数的快速选择任务. 当我们搭建完成深度学习模型结构之后,我们在训练模型的过程中,有很大一部分工作主要是通过验证集评估指标,来不断调节模型的超参数,这是比较耗

随机推荐