代码性能优化(3)——聊聊多线程

news2024/11/17 17:36:21

    代码的性能优化,有些是从逻辑层面进行的,比如同时对50W个人发放奖励,可以改成用户登录的时候,自动领取有没奖励,或者统计每日的每个业务员的销售额和实时累积的销售额,将实时sum函数改成,每一笔单独存在某个字段里面。有些是从硬件层面优化的,比如增加服务器的内存空间和内核数量。而有些是从代码的运行线程考虑的,只要有等待时间,我们将其放入等待仓库,让不用等待的线程先跑。

       所以我们需要理解线程的逻辑。这个关系到语种的差距,还有深刻理解为什么php比java这种语言种类的差距。如果把进程看成是一座工厂,这个工厂是要完成目标的生产任务,在这个工厂里面,有厂房(内存空间)仓库(文件资源),每条流水线都在进行生产任务的生产。而这里的每条流水线,就是线程。在常规的PHP里面,在传统的网站,基本就是一个访问,直接请求对应了一个线程,独占了这个工厂。如果需要在这个工厂里面管理多条生产线,PHP是无能为力的,所以这个PHP在占据了方便和效率高,但是整体市场也在逐步萎缩。而swoole和workerman就是在这个方便做出努力。

   在这个过程里面,每一条生产线的运行都是需要执行时间的。而且在执行A线程的时候,B/C/D线程都只能等待排队,这就严重的制约了其并发性能。A/B/C/D任务基本都差不多,除了请求参数有不同,其他逻辑完全一样。但是PHP没有响应过来的情况下,只能排队执行。这里以一个最常见的爬虫为例子,我们要抓取10W个页面的数据,需要采集页面后,做一些列逻辑处理,最后存储。按照PHP的做法,我们只能一条路走到黑,或者写10个PHP文件,执行10次PHP,每个PHP的采集范围都不同。

 而如果切换到python/node/go/java里面,我们只需要运行一个文件,直接开启10个线程,同时让10个线程分别采集不同范围的页码即可。类似的场景,相同事情必须另外开进程(也就是开工厂,重新部署一条生产线),这个代价就非常大。从这里可以看出,多线程可以提高CPU的利用率,加快程序的响应速度,同时提高程序的并发能力,更加有效利用系统资源

  然后马上有个疑问,多线程这么牛逼的能力,为啥PHP没有呢?这与PHP本身早起的理念关系就很大,PHP就是追求简单和快速,引入了多条生产线,在现实工厂里面需要额外增加管理人员,还要解决不同生产线同时用到了仓库互相吵架怎么处理,同时用到了厂房又怎么协调,最后组装产品的时候,又怎么管理。

而在程序里面,表现出来就是增加了内存开销,毕竟,每个线程需要记录线程寄存器等信息,线程太多,会导致内存消耗过大,上下文的切换开销,资源竞争问题,俩个线程同时使用到了一个东西需要处理,还有调试和测试复杂度也提升,因为线程执行顺序可能有影响,代码错误如果与线程执行顺序有关联,会导致代码出现的错误可能出现幽灵错误,就是有时候有有时候又没有。

       想到这里,其实我们就能理解到我们平时遇到的一些只发生过一次的错误,很可能就是多线程异常产生的。而这些在PHP理念里面,都是非常繁琐的,它直接将这个多线程概念摒弃了。这样导致了,我们学习使用PHP非常的爽,入门很快,学习也很快,但是劣势就是爽过了,发现很多东西都受到了限制。导致不得不通过其他的语言来替代。

  到这里,其实已经大体解释清楚了进程和线程的关系,还有多线程和单线程的优势和劣势。包括PHP本身设计的简易思路,放弃了多线程的管理而提升自己的简单程度。 最后我们来使用python实现一个简单的多线程,尝试着跑一遍代码程序,彻底理解多线程过程里面到底是怎么跑的,我们写爬虫的时候,特别是一些静态页面的采集请求,就可以采用多线程的方式执行,

  import threading
import time
# 定义一个函数,用于在线程中执行
def print_numbers():
    for i in range(5):
        time.sleep(1)  # 模拟一些耗时的操作
        print(f"Thread 1: {i}")

# 定义另一个函数,用于在另一个线程中执行
def print_letters():
    for letter in ['A', 'B', 'C', 'D', 'E']:
        time.sleep(3)  # 模拟一些耗时的操作
        print(f"Thread 2: {letter}")

# 创建两个线程
thread1 = threading.Thread(target=print_numbers)
thread2 = threading.Thread(target=print_letters)
# 启动线程
thread1.start()
thread2.start()
# 等待所有线程完成
thread1.join()
thread2.join()
print("Both threads have finished executing.")

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

24种设计模式介绍与6大设计原则(电子版教程)

前言 您是一个初级的 coder,可以从中领会到怎么设计一段优秀的代码;您是一个高级程序员,可以从中全面了解到设计模式以及 Java 的边角技术的使用;您是一个顶级的系统分析师,可以从中获得共鸣,寻找到项目公共问题的解决…

StarRock3.3 安装部署

服务器前置要求: 1、内存>32GB 2、JDK 8 is not supported, please use JDK 11 or 17 1、安装 wget https://releases.starrocks.io/starrocks/StarRocks-3.3.0.tar.gz tar zxvf StarRocks-3.3.0.tar.gz 2、FE服务启动 2.1 配置FE节点(默认配置,…

dns和 openELB

DNS yum -y install bind允许其他的主机来监听,允许其他的主机来查询,改这两个地方就行了。 把需要解析的文件都添加进来,cp -p的意思是保留原来的权限控制 注意本地dns放在 DNS1 二、负载均衡 OpenELB Layer2 模式 BGP模式 OpenELB …

DBeaver使用SQL脚本编辑器

文章目录 1 新建脚本2 选择数据库3 编写脚本【按行执行】参考 1 新建脚本 2 选择数据库 3 编写脚本【按行执行】 光标放到需要执行的行上,点击【最上面的按钮】 或者选中某片代码,然后执行 也可以编写一个脚本然后执行 参考 dbeaver安装和使用教程 …

Linux文件恢复

很麻烦 一般还是小心最好 特别恢复的时候 可能不能选择某个文件夹去扫描恢复 所以 删除的时候 用rm -i代替rm 一定小心 以及 探索下linux的垃圾箱机制 注意 一定要恢复到不同文件夹 省的出问题 法1 系统自带工具 debugfs 但是好像不能重启? testdisk 1、安装 …

酒店智能门锁接口pro[0922]D801 对接收银-SAAS本地化-未来之窗行业应用跨平台架构

proUSB接口函数[0922中性版]-D801 调用函数库: 提供Windows下的32位动态连接库proRFL.DLL,函数使用详细说明 //-----------------------------------------------------------------------------------// 功能:读DLL版本,不涉…

【大数据】:hdfs相关进程启停管理命令

HADOOP_HOME/sbin/start-dfs.sh,一键启动HDFS集群 执行原理: 在执行此脚本的机器上,启动SecondaryNameNode 读取core-site.xml内容(fs.defaultFS项),确认NameNode所在机器,启动NameNode 读取wor…

AI变现:科技与商业化的交织

随着科技的飞速发展,人工智能(AI)已经从科幻电影中的概念走进了现实生活的各个领域,深刻影响着经济、社会与科技的发展。AI不仅代表着技术的革新,更是推动商业变现的重要力量。本文将深入剖析AI的发展历程,…

数据结构(5.3_5)——二叉树的线索化

第一种寻找中序前驱方法 中序线索化 本质上就是一次中序遍历,只不过需要在一边遍历一边处理结点线索化 代码: //全局变量pre 指向当前访问结点的前驱 ThreadNode* pre NULL;struct ElemType {int value; };//线索二叉树结点 typedef struct ThreadNode…

姜夔,师法自然的不仕道人

姜夔(ku),字尧章,号白石道人,约生于南宋绍兴二十四年(公元1154年),卒于南宋嘉定十四年(公元1221年),享年67岁。他的艺术成就涵盖了诗词、散文、书…

JAVA (IO流) day7.25

ok了家人们今天继续学习io流,废话不多说,我们一起看看吧 一.File类 1.1 File类的概述 通过 File 类与 IO 流进行搭配使用就可以通过 Java 代码将数 据从内存写入到硬盘文件 或者从硬盘文件读取到内存 中。 File 类就是文件和目录路径名的抽象表示形式…

ElasticSearch(es)倒排索引

目录 一、ElasticSearch 二、倒排索引 1. 正向索引 2. 倒排索引 具体细节 1. 文档分析 2. 索引构建 3. 索引存储 4. 词条编码 5. 索引优化 6. 查询处理 示例 总结 3. 正向和倒排 三、总结 倒排索引的基本概念 为什么倒排索引快 一、ElasticSearch Elasticsear…

让开发者生活更轻松的 JavaScript 字符串方法

前端岗位内推来了 JavaScript 最初被引入作为一种简单的客户端脚本语言,但现在,它已经成为一种真正的 WORA(一次编写到处运行)语言,使开发者能够构建桌面、移动、电视、CLI 和嵌入式应用程序。JavaScript 的初学者友好…

HiveSQL题——炸裂+开窗

一、每个学科的成绩第一名是谁? 0 问题描述 基于学生成绩表输出每个科目的第一名是谁呢? 1 数据准备 with t1 as(selectzs as name,[{"Chinese":80},{"Math":70}],{"English"…

IOS-04 Swift 中数组、集合、字典、区间、元组和可选类型

在 Swift 编程语言中,数据结构和类型的合理运用对于高效编程至关重要。接下来,我们将深入探讨数组、集合、字典、区间、元组和可选类型的相关知识。 一、数组(Array) (一)元素定义 可以通过多种方式定义数…

关于 OSPF 序列号范围 0x80000001-0x7FFFFFFF 正本清源

注:机翻,未校对。 正本:RFC 2328 OSPF Version 2 中相关解释 April 1998 12.1.6. LS sequence number 12.1.6. 序列号 The sequence number field is a signed 32-bit integer. It is used to detect old and duplicate LSAs. The space …

【React】详解 React Hooks 使用规则

文章目录 一、Hooks 的基本原则1. 只在最顶层调用 Hooks2. 只在 React 函数组件和自定义 Hooks 中调用 Hooks 二、常见 Hooks 及其使用规则1. useState2. useEffect3. useContext4. useReducer5. useMemo6. useCallback 三、常见错误及其解决方案1. 在条件语句中调用 Hooks2. 在…

「C++系列」数组

文章目录 一、数组1. 声明数组2. 初始化数组3. 访问数组元素4. 遍历数组注意事项示例代码 二、多维数组1. 声明二维数组2. 初始化二维数组3. 访问二维数组元素4. 遍历二维数组注意事项示例代码 三、指向数组的指针1. 声明指向数组的指针2. 通过指针访问数组元素3. 指针和数组的…

文件上传漏洞(ctfshow web151-161)

Web151 F12修改源代码 exts后面png改为php 这样就可以上传php的文件了 Web152: 考点:后端不能单一校验 就是要传图片格式,抓个包传个png的图片 然后bp抓包修改php后缀解析 然后放包 Web153-web156 在php代码中可以使用“{}”代替“[]” …

Go语言实战:基于Go1.19的站点模板爬虫技术解析与应用

一、引言 1.1 爬虫技术的背景与意义 在互联网高速发展的时代,数据已经成为新的石油,而爬虫技术则是获取这种“石油”的重要工具。爬虫,又称网络蜘蛛、网络机器人,是一种自动化获取网络上信息的程序。它广泛应用于搜索引擎、数据分…