我的编程空间,编程开发者的网络收藏夹
学习永远不晚

深入理解 Python 中的多线程 新手必看

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

深入理解 Python 中的多线程 新手必看

示例1
我们将要请求五个不同的url:
单线程


import time
import urllib2
 
defget_responses():
  urls=[
    ‘http://www.baidu.com',
    ‘http://www.amazon.com',
    ‘http://www.ebay.com',
    ‘http://www.alibaba.com',
    ‘http://www.lsjlt.com'
  ]
  start=time.time()
  forurlinurls:
    printurl
    resp=urllib2.urlopen(url)
    printresp.getcode()
  print”Elapsed time: %s”%(time.time()-start)
 
get_responses()

输出是:
http://www.baidu.com200
http://www.amazon.com200
http://www.ebay.com200
http://www.alibaba.com200
http://www.lsjlt.com200
Elapsed time:3.0814409256

解释:
url顺序的被请求
除非cpu从一个url获得了回应,否则不会去请求下一个url
网络请求会花费较长的时间,所以cpu在等待网络请求的返回时间内一直处于闲置状态。
多线程


import urllib2
import time
from threading import Thread
 
classGetUrlThread(Thread):
  def__init__(self, url):
    self.url=url
    super(GetUrlThread,self).__init__()
 
  defrun(self):
    resp=urllib2.urlopen(self.url)
    printself.url, resp.getcode()
 
defget_responses():
  urls=[
    ‘http://www.baidu.com',
    ‘http://www.amazon.com',
    ‘http://www.ebay.com',
    ‘http://www.alibaba.com',
    ‘http://www.lsjlt.com'
  ]
  start=time.time()
  threads=[]
  forurlinurls:
    t=GetUrlThread(url)
    threads.append(t)
    t.start()
  fortinthreads:
    t.join()
  print”Elapsed time: %s”%(time.time()-start)
 
get_responses()

输出:
http://www.lsjlt.com200
http://www.baidu.com200
http://www.amazon.com200
http://www.alibaba.com200
http://www.ebay.com200
Elapsed time:0.689890861511

解释:

意识到了程序在执行时间上的提升
我们写了一个多线程程序来减少cpu的等待时间,当我们在等待一个线程内的网络请求返回时,这时cpu可以切换到其他线程去进行其他线程内的网络请求。
我们期望一个线程处理一个url,所以实例化线程类的时候我们传了一个url。
线程运行意味着执行类里的run()方法。
无论如何我们想每个线程必须执行run()。
为每个url创建一个线程并且调用start()方法,这告诉了cpu可以执行线程中的run()方法了。
我们希望所有的线程执行完毕的时候再计算花费的时间,所以调用了join()方法。
join()可以通知主线程等待这个线程结束后,才可以执行下一条指令。
每个线程我们都调用了join()方法,所以我们是在所有线程执行完毕后计算的运行时间。

关于线程:

cpu可能不会在调用start()后马上执行run()方法。
你不能确定run()在不同线程建间的执行顺序。
对于单独的一个线程,可以保证run()方法里的语句是按照顺序执行的。
这就是因为线程内的url会首先被请求,然后打印出返回的结果。

实例2

我们将会用一个程序演示一下多线程间的资源竞争,并修复这个问题。


from threading import Thread
 
#define a global variable
some_var=0
 
classIncrementThread(Thread):
  defrun(self):
    #we want to read a global variable
    #and then increment it
    globalsome_var
    read_value=some_var
    print”some_var in %s is %d”%(self.name, read_value)
    some_var=read_value+1
    print”some_var in %s after increment is %d”%(self.name, some_var)
 
defuse_increment_thread():
  threads=[]
  foriinrange(50):
    t=IncrementThread()
    threads.append(t)
    t.start()
  fortinthreads:
    t.join()
  print”After 50 modifications, some_var should have become 50″
  print”After 50 modifications, some_var is %d”%(some_var,)
 
use_increment_thread()

多次运行这个程序,你会看到多种不同的结果。
解释:
有一个全局变量,所有的线程都想修改它。
所有的线程应该在这个全局变量上加 1 。
有50个线程,最后这个数值应该变成50,但是它却没有。
为什么没有达到50?
在some_var是15的时候,线程t1读取了some_var,这个时刻cpu将控制权给了另一个线程t2。
t2线程读到的some_var也是15
t1和t2都把some_var加到16
当时我们期望的是t1 t2两个线程使some_var + 2变成17
在这里就有了资源竞争。
相同的情况也可能发生在其它的线程间,所以出现了最后的结果小于50的情况。
解决资源竞争


from threading import Lock, Thread
lock=Lock()
some_var=0
 
classIncrementThread(Thread):
  defrun(self):
    #we want to read a global variable
    #and then increment it
    globalsome_var
    lock.acquire()
    read_value=some_var
    print”some_var in %s is %d”%(self.name, read_value)
    some_var=read_value+1
    print”some_var in %s after increment is %d”%(self.name, some_var)
    lock.release()
 
defuse_increment_thread():
  threads=[]
  foriinrange(50):
    t=IncrementThread()
    threads.append(t)
    t.start()
  fortinthreads:
    t.join()
  print”After 50 modifications, some_var should have become 50″
  print”After 50 modifications, some_var is %d”%(some_var,)
 
use_increment_thread()

再次运行这个程序,达到了我们预期的结果。
解释:
Lock 用来防止竞争条件
如果在执行一些操作之前,线程t1获得了锁。其他的线程在t1释放Lock之前,不会执行相同的操作
我们想要确定的是一旦线程t1已经读取了some_var,直到t1完成了修改some_var,其他的线程才可以读取some_var
这样读取和修改some_var成了逻辑上的原子操作。
实例3
让我们用一个例子来证明一个线程不能影响其他线程内的变量(非全局变量)。
time.sleep()可以使一个线程挂起,强制线程切换发生。


from threading import Thread
import time
 
classCreateListThread(Thread):
  defrun(self):
    self.entries=[]
    foriinrange(10):
      time.sleep(1)
      self.entries.append(i)
    printself.entries
 
defuse_create_list_thread():
  foriinrange(3):
    t=CreateListThread()
    t.start()
 
use_create_list_thread()

运行几次后发现并没有打印出争取的结果。当一个线程正在打印的时候,cpu切换到了另一个线程,所以产生了不正确的结果。我们需要确保print self.entries是个逻辑上的原子操作,以防打印时被其他线程打断。
我们使用了Lock(),来看下边的例子。


from threading import Thread, Lock
import time
 
lock=Lock()
 
classCreateListThread(Thread):
  defrun(self):
    self.entries=[]
    foriinrange(10):
      time.sleep(1)
      self.entries.append(i)
    lock.acquire()
    printself.entries
    lock.release()
 
defuse_create_list_thread():
  foriinrange(3):
    t=CreateListThread()
    t.start()
 
use_create_list_thread()

这次我们看到了正确的结果。证明了一个线程不可以修改其他线程内部的变量(非全局变量)。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

深入理解 Python 中的多线程 新手必看

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

深入理解 Python 中的多线程 新手必看

示例1 我们将要请求五个不同的url: 单线程import time import urllib2defget_responses():urls=[‘http://www.baidu.com',‘http://www.amazon.com'
2022-06-04

java多线程编程必备volatile与synchronized深入理解

这篇文章主要介绍了java多线程编程必备volatile与synchronized的深入理解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-05-15

深入浅析python中的多进程、多线程、协程

进程与线程的历史我们都知道计算机是由硬件和软件组成的。硬件中的CPU是计算机的核心,它承担计算机的所有任务。 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资源的管理和分配、任务的调度。 程序是运行在系统上的具有某种功能的软件,比
2022-06-04

如何深入理解Java多线程与并发框中线程的状态

本篇文章给大家分享的是有关如何深入理解Java多线程与并发框中线程的状态,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。1. 新建状态(New)万事万物都不是凭空出现的,线程也一
2023-06-05

如何深入理解Java多线程与并发框中的CAS

如何深入理解Java多线程与并发框中的CAS,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。CAS实现原理CAS 是 CompareAndSwap 的缩写,意思是
2023-06-05

如何深入理解Java多线程与并发框中线程和进程的区别

如何深入理解Java多线程与并发框中线程和进程的区别,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。线程和进程的区别1. 资源调度单位在计算机中,进程是程序运行所
2023-06-05

深入解析Python中的线程同步方法

同步访问共享资源 在使用线程的时候,一个很重要的问题是要避免多个线程对同一变量或其它资源的访问冲突。一旦你稍不留神,重叠访问、在多个线程中修改(共享资源)等这些操作会导致各种各样的问题;更严重的是,这些问题一般只会在比较极端(比如高并发、生
2022-06-04

如何深入理解最新Python中的Match Case

如何深入理解最新Python中的Match Case,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。有些人仍然认为 Python 不需要“switch-case”语法。 甚至 G
2023-06-25

如何深入理解Java多线程与并发框中的volatile关键字

本篇文章为大家展示了如何深入理解Java多线程与并发框中的volatile关键字,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。概念把对 volatile变量的单个读/写,看成是使用 同一个监视器锁
2023-06-05

必学!深入解析Python中常用的流程控制语句

小白必看!Python中常用的流程控制语句解析,需要具体代码示例导语:Python作为一门简洁而强大的编程语言,具有简单易学的特点,适合初学者入门。而流程控制语句是编程中的核心,通过掌握流程控制语句,可以让你的程序编写更加灵活和高效。本文
必学!深入解析Python中常用的流程控制语句
2024-01-20

怎样深入理解Java多线程与并发框中的synchronized 关键字

怎样深入理解Java多线程与并发框中的synchronized 关键字,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一、Class文件与对象对象头 32位JVM的对象头二、sy
2023-06-05

操作系统多线程解析:深入了解并行处理的机制

多线程是操作系统中一种重要的概念,它是实现并行处理的基础。本文将深入探讨多线程的机制,包括多线程的创建、调度、同步和通信等方面,并通过演示代码示例来说明这些概念。
操作系统多线程解析:深入了解并行处理的机制
2024-02-24

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录