「Python网络编程」如何让蔡徐坤同时唱跳rap篮球/初识多线程(二)

博主前言:

通过第一篇文章的学习,读者已经认识了网络编程中的套接字编程,已经具备了实现基于TCP协议和基于UDP协议网络编程中客户端的实现。第二篇文章打算让读者感受一下多线程的魅力,通过仔细阅读本篇文章完全可达到一文入门多线程的目的。

1. 几个基本概念

1.1 单核CPU与多核CPU

CPU(central processing unit),即中央处理器,是作为计算机系统的运算和控制核心,是信息处理、程序运行的最终执行单元。
所谓单核CPU就是指同一时刻计算机只能执行一件事情。即电脑在同一时刻只运行一种程序。
那么多核CPU就是指同一时刻计算机可以执行多件事情。即电脑在同一时刻可执行多种程序。在这里插入图片描述

1.2 并行与并发

我相信读到这儿读者肯定是有疑问的,为什么在配置单核CPU的计算机上既可以听音乐,同时又可以打开QQ聊天,同时还可以挂着游戏呢?
这一切的原因都是因为CPU运行的速度实在是太快了,一秒钟可以执行上百万次。在单核CPU的计算机上,我们先把音乐播放的软件拿来执行,让它执行0.0001s,然后再把QQ的程序拿来执行0.0001s,最后再把游戏的程序拿来执行0.0001s,循环往复。虽然我们执行的时间只有0.0001s,但是在CPU眼里,这个时间已经足够长了,所以达到了我们视觉上的效果,好像音乐、QQ、游戏同时在运行的样子。类似于现实生活中的翻书动画一般,如下图所示。
这是一种伪多任务的情况,对于CPU这种雨露均沾的操作,我们有一个名字叫做:时间片轮转
同时,对于这种假的多任务,我们称之为并发在这里插入图片描述
那么是否存在真的多任务呢?
答案是肯定的,多核CPU就可以实现真的多任务。当三个程序在配置四核CPU的计算机上运行的时候,就可以称之为真的多任务。我们将这种真正的多任务称之为并行
但是在实际的生活中,我们在电脑上运行的程序数量往往大于CPU的核数,也就是说,我们在现实生活中称的多任务,99%指的都是并发,而不是并行。

2. 多线程

线程是实现多任务的一种手段。通俗来讲,一个程序运行起来之后,一定有一个执行代码流程的次序,这个次序,就称之为线程。

2.1 单线程

单线程指的是在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行。
用一句话来形容单线程就是:单线程就是一心一意,用情专一的痴情少年。
我们通过一段代码来感受一下单线程。

# 引入time模块,定时使用
import time
# 定义唱跳rap篮球的函数
def sing():for i in range(3):			# 用for循环来模拟实现print("我是蔡徐坤,我会唱。")time.sleep(1)def dance():for i in range(3):print("我是蔡徐坤,我会跳。")time.sleep(1)def rap():for i in range(3):print("我是蔡徐坤,我会rap。")time.sleep(1)def basketball():for i in range(3):print("我是蔡徐坤,我会篮球。")time.sleep(1)
# 定义主函数
def main():		sing()dance()rap()basketball()if __name__ == '__main__':main()

通过执行上述代码,运行结果如下图,我们可以看到一个会唱跳rap篮球的蔡徐坤,但是这个蔡徐坤同一时刻只能干一件事情,唱的时候不会跳,跳的时候不会rap,rap的时候不能篮球。
在这里插入图片描述
这就是一个单线程的程序代码,在执行dance函数之前,sing函数一定要执行完整,代码的执行按照规定的连续顺序依次执行,前面处理好,后面才能执行。那么,我们要怎样才能使多个函数“一起”执行呢?‘

2.2 多线程

要让多个函数“一起”执行,就要使用多线程了。
这里我们学习到一个新的模块:threading模块
我们修改一下上述代码,将其多线程化。

import threading			# 引入threading模块
import timedef sing():for i in range(3):print("我是蔡徐坤,我会唱。")time.sleep(1)def dance():for i in range(3):print("我是蔡徐坤,我会跳。")time.sleep(1)def rap():for i in range(3):print("我是蔡徐坤,我会rap。")time.sleep(1)def basketball():for i in range(3):print("我是蔡徐坤,我会篮球。")time.sleep(1)def main():test1 = threading.Thread(target=sing)  #创建一个Tread对象test2 = threading.Thread(target=dance)  #创建一个Tread对象test3 = threading.Thread(target=rap)  #创建一个Tread对象test4 = threading.Thread(target=basketball)  #创建一个Tread对象test1.start()  #创建子线程test2.start()  #创建子线程test3.start()  #创建子线程test4.start()  #创建子线程if __name__ == '__main__':main()

通过运行上述代码,我们可以清楚的认识到多线程和单线程的区别,不禁在心中大喊一声“多线程牛逼”。
实际上,多线程的使用更加广泛和深刻,结合我们上篇文章学习的套接字编程的内容,我们已经具备了编写实现一个基于UDP协议或TCP协议聊天室功能的小程序的能力,希望读者们可以实践实践。

2.3 主线程和子线程

在threading模块中,有一个enumerate的函数,此函数返回类型为列表类型,列表元素是线程的内容,元素的个数是线程的数量。我们可以通过enumerate函数证明,当调用Thread类的构造方法创建对象时,子线程还没有被创建,只有当该对象调用start方法时,子线程才被创建。

import threading
import timedef test():for i in range(3):print("This is a test")time.sleep(1)def main():print(threading.enumerate())	# 调用enumerate函数,查看在创建Thread对象之前的当前线程test1 = threading.Thread(target=test)print(threading.enumerate())	# 调用enumerate函数,查看在创建Thread对象之后的当前线程test1.start()print(threading.enumerate())	# 调用enumerate函数,查看Thread对象开始之后的当前线程if __name__ == '__main__':main()

在这里插入图片描述
我们在Thread对象创建的前、后,以及Thread对象调用开始函数之后,分别调用enumerate函数,查看当时线程情况,可得到以上图示情况。
此结果说明,我们在创建Thread对象的时候没有创建子线程,只有在Thread对象调用start函数时,子线程才被创建,并开始执行其相应代码。而且只有当子线程的代码运行结束之后,主线程才结束运行。

3. 共享全局变量

全局变量,即定义在函数外部的变量。每一个实例函数都可以对全局变量进行使用,我们想象一个情况,当子线程1和子线程2同时对一个全局变量进行使用修改的时候,其结果究竟会是怎样呢?

import threading
# 定义一个全局变量a,赋值为0
a = 0
def test1():# 修改全局变量a的值global afor i in range(100):a = a+1print("经过test1后a的值为:",a)def test2():# 修改全局变量a的值global afor i in range(100):a = a+1print("经过test2后a的值为:",a)def main():t1 = threading.Thread(target=test1)t2 = threading.Thread(target=test2)t1.start()		# 创建子线程1t2.start()		# 创建子线程2if __name__ == '__main__':main()

在这里插入图片描述
上段代码创建了一个子线程1和子线程2,两个线程同时对全局变量a进行加1操作,所示结果如上图。结果说明,当两个线程同时对全局变量进行使用的时候,可以共享使用。可,当我们将循环次数加到一百万时,运行结果又会如何呢?
在这里插入图片描述
当我们把循环次数加到足够大的时候,结果将会让我们大吃一惊!这是为什么呢?
这是因为我们在使用全局变量的时候,系统会解析成很多句话。

  1. 获取全局变量a的值
  2. 把获取的全局变量a值+1
  3. 把第2步所得的结果存储到全局变量a中

所以,当程序调用全局变量的时候,有可能子线程1执行到第二步的时候,子线程2就开始执行第一步,此时子线程2获取的全局变量a的值为子线程1此次执行调用的全局变量的值相同,因为子线程1此次执行没有调用第三步存储第二步的值。(读者请重点理解这段话)

3.1 互斥锁

为了防止当多个线程几乎同时修改某一个共享数据的时候,造成数据丢失,我们引入了互斥锁,进行同步控制。
互斥锁状态:锁定/非锁定
当某个线程更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成非锁定,其他线程才能再次锁定该资源,互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。
我们把互斥锁加入上诉代码:

import threading
# 定义一个全局变量a,赋值为0
a = 0
# 创建互斥锁
mutex = threading.Lock()def test1():global a#锁定mutex.acquire()for i in range(1000000):a = a+1# 释放mutex.release()print("经过test1后a的值为:",a)def test2():global a#锁定mutex.acquire()for i in range(1000000):a = a+1# 释放mutex.release()print("经过test2后a的值为:",a)def main():t1 = threading.Thread(target=test1)t2 = threading.Thread(target=test2)t1.start()t2.start()if __name__ == '__main__':main()

我们调用threading模块的Lock函数创建互斥锁对象,同时将资源使用acquire函数上锁,当执行完毕后,调用release函数释放资源。
若上锁之前没有被上锁,那么此时上锁成功。如果上锁之前已经被上锁了,那么此时会堵塞在这里,直到该资源解锁。

3.2 死锁

在多线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源就会造成死锁。
如何有效避免死锁是开发者在实际开发过程中必须注意的事项。通常避免死锁的方法有

  1. 银行家算法
  2. 添加超时时间

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/45652.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

蔡徐坤用户画像

来源:挖数 作者:挖数 互联网行业经常会做用户调研,通过线下访谈和线上埋点等方式收集用户数据后,最终形成产品主流用户的性别、年龄、职业、喜好、城市等标签数据,这个过程称为“用户画像”。 如果蔡徐坤是一款互联网产…

小文智能结合ChatGPT的产业未来

最近几个月,由人工智能实验室OpenAI发布的对话式大型语言模型ChatGPT在国内外各大平台掀起了一阵AI狂潮。短短几天时间,其用户量就突破了百万大关,注册用户之多一度导致服务器爆满。 继AI画图之后,ChatGPT成为了新的顶流&#xf…

chatgpt赋能python:Python中绘制图形

Python中绘制图形 Python有很多强大的库可以用来绘制各种形式的图形。在这篇文章中,我们将介绍几个最常用的库,包括Matplotlib、Seaborn和Plotly。我们还将介绍如何用这些库绘制各种不同类型的图形。 Matplotlib Matplotlib是一个基于Python的绘图库&…

大模型带来的Web复兴,会是昙花一现吗?

大家是不是对GPT、对话式AI、生成式AI之类的话题,已经有点审美疲劳了? 写这篇文章之前,我有点犹豫,究竟还要不要接着讨论GPT了。最终决定写,是觉得个人用户、开发者,以及正在紧锣密鼓训大模型的AI公司和云厂…

【主流Chat模型的申请入口和方法】

主流Chat模型的申请入口和方法 一、申请New Bing二、申请内测文心一言三、申请内测Claude四、谷歌家的Bard五、Adobe Firefly六、GitHub Copilot chat七、通义千问八、360智脑一、申请New Bing 注册一个 outlook 邮箱,很简单,2分钟就可搞定~下载 Edge DEV 浏览器,用刚刚的邮…

券商要知道的港美股软件交易系统板块展示图

目前,国内做港美股软件开发的公司不超过5家,他们中不乏有些是行业的领头者,服务和技术可以说能让券商感到满意的,其中也有刚入门的技术不成熟,从设计上不够科学、系统的稳定性,也没有那么好。 一套完整的港…

用AkShare库获取A股股票数据—获取实时A股数据

前面给大家介绍了如何用Tushare获取A股股票数据,但是现在使用Tushare会受到积分限制,没有获得积分使用起来也麻烦。今天再给大家介绍一个免费的开源数据库AKShare。 AKShare 是基于 Python 的财经数据接口库, 目的是实现对股票、期货、期权、基金、外汇…

用AkShare获取沪深京A股所有股票历史数据

前面章节已经介绍了如何用AkShare调用A股实时的数据,但是在我们量化投资过程中,经常会需要用到全量数据(即所有A股的历史数据)。接下来我们讲讲用AkShare获取A股所有股票历史数据。 首先,我们通过AkShare的东财实时行情…

IOS 股票K线图的实现

2015-09-04 by 木易哥哥  智者精选,每天获取励志认知能量 www.5izhjx.com 写了lines、RKLineView、getData三个对象完成实现。 首先开始调用 rkLine [[RKLineViewalloc]init]; CGRect frame riKView.frame; frame.origin CGPointMake(0,5); frame.size CGSizeM…

【ChatGPT里的平行宇宙

除非你一直生活在岩石下,否则你肯定听说过ChatGP。 你可能知道它在解决 IQ 测试、解决 leetcode 问题或帮助人们编写 LateX 方面的能力。 它是人们检索各种信息和解决繁琐任务(如文案写作)的绝佳资源! 今天,Frederic …

AIGC将颠覆设计界?!今晚直播间解密AIGC之图像生成史

从DeepFake、风格迁移到 Midjourney、DALLE ... AIGC的应用一次又一次带给我们惊喜 这些背后的蕴藏着哪些原理? 赶快加入AIGC图像生成直播课! 探索AI生成艺术的奥秘 2月28日-3月7日每周二晚8点 系列直播课「扫码报名」啦! 扫描下方二维码&…

chatgpt赋能python:Python导入照片的SEO优化指南

Python导入照片的SEO优化指南 在当今的数字时代,网站的视觉效果已经成为重要的一环。而在网站上展示照片既可以吸引用户的眼球,又可以更好地传达信息。然而,对于搜索引擎来说,照片是无法读懂的,它们需要依靠一些描述性…

chatgpt赋能python:Python怎么导入照片

Python怎么导入照片 Python是一种高级编程语言,可用于创建各种应用程序和项目。当涉及到处理图像时,Python也非常有用。在本文中,我们将介绍如何使用Python导入照片,并附带一些有关如何使用SEO优化您的图像的提示。 介绍 在开始…

作曲 app android,文艺又好玩!安卓作曲达人App试用体验

说起文艺,自然是离不开琴棋书画。喜欢文艺的机友为数不少,安卓平台也有不少关于琴棋书画的App。今天要介绍的这款安卓作曲达人App,可以说比它技术的没它文艺,比它文艺的没它技术。无论你懂不懂乐理,看着一个个音符在你…

妙计高招:短信验证码接收教程图像处理AI黑科技汇总

随着人工智能技术的越来越火爆,我们在使用国内外应用提供的功能时经常会用到短信验证功能,对于我们而言,轻松搞好短信验证没有那么容易,本篇文章对几篇接收验证码的教程进行了汇总并附带了一些主流AI软件的使用教程,希…

ChatGPT真的泰酷啦!泰酷啦!

马总来中国啦!最近chatGPT有多火,就不用我多说了。。。 真的佩服Musk,其公司的产品每个都能出圈,虽然OpenAI只是他投的一个项目,但总感觉吸了他欧气的项目就总能火。就看会不会被twitter砸了招牌。但即便twitter垮了&a…

尝试使用chatgpt帮我优化sql

尝试写一些sql看看chatgpt写的和自己写的哪里不一样,帮助我打开思路。 第一题 数据库中有个员工表emp,建表语句如下: create table emp_his (emp_id number, emp_name varchar(50)); 表中存在重复记录(根据emp_id来判断),用SQL如何查出存在重复的 emp_id&#xff…

java 大结果_java三大工厂结果总览

2018-11-02 21:27:18 开始写 谢谢、Thank you、Salamat Do(撒拉玛特朵)、あリがCm o*n(嘉蒙)とゥ(阿里嘎都)、????? (勘三哈咪瘩)、terima Kasih(得力马卡系)、kob-khun(寇布库恩)、dhanyavaad(达尼阿瓦德)、toda(透达)、te?ekkr ederim(特谢库尔埃戴里姆)、Dzie,kuje(以…

[教师资格证-中学笔试-裸考过关]教育知识与能力必背知识点(技巧)

裸考过了综测和专业课,都是刚刚达线,而教育知识与常识需要背,所以68分没过。。。很惨.。。就差了一个选择题。 所以再次考试的时候还是准备了下,至少得看看考什么,不然真的太惨了,68.。。。不过其他两门裸考…