讲师中心 微信公众号
AI工具推荐 视频效率加速

线程:如何以性能为目标来定义和限制执行?

大静大大_4568

大静大大_4568

发布时间:2024-11-13 16:33:13

|

1095人浏览过

|

来源于dev.to

转载

线程:如何以性能为目标来定义和限制执行?

线程,一种有助于开发现代高性能解决方案并成为不可或缺的工具。无论使用哪种语言,并行执行任务的能力都具有很大的吸引力。但显然有本叔叔的名言:“能力越大,责任越大。”如何以最佳方式使用该解决方案,以实现性能、更好地利用资源和应用程序健康?首先,有必要了解本主题的基本概念。

什么是“线程”?

线程是操作系统中进程执行的基本单位。它们允许程序在同一进程中同时执行多个操作。每个线程与主进程共享相同的内存空间,但可以独立执行,这对于可以并行执行的任务非常有用,例如输入/输出(i/o)操作、复杂计算或数据用户界面。 .

在许多系统上,线程由操作系统管理,操作系统为每个线程分配 cpu 时间并管理它们之间的上下文切换。在java、python、c++等编程语言中,都有方便创建和管理线程的库和框架。

为什么要使用线程?

线程主要用于提高程序的效率和响应能力。使用线程,尤其是后端的原因是:

  • 并行:线程允许您同时执行多个操作,从而更好地利用可用的 cpu 资源,特别是在具有多个内核的系统上。

  • 性能:在 i/o 操作中,例如读写文件或网络通信,线程可以通过允许程序在等待这些任务完成的同时继续执行其他任务来帮助提高性能操作。

  • 模块化:线程可用于将程序划分为更小、更易于管理的部分,每个部分执行特定的任务。

但是,仔细管理线程非常重要,因为不正确的使用可能会导致竞争条件、死锁和调试困难等问题。为了更好地管理它们,使用了线程池解决方案。

什么是线程池以及为什么需要它?

线程池是一种软件设计模式,涉及创建和管理可重复使用来执行任务的线程池。线程池不会为每个任务重复创建和销毁线程,而是维护固定数量的线程,准备根据需要执行任务。这可以显着提高需要处理许多并发任务的应用程序的性能。使用线程池的优点是:

python学习
python学习

Python 编程学习助手 skill,面向零基础用户。 当用户表达以下意图时触发: - 学习 Python 基础概念(变量、数据类型、循环、函数、类等) - 请求 Python 练习题或测验 - 请求审查或调试 Python 代码 - 请求 Python 项目实战指导(爬虫、数据分析、Web 开发等入门项目) - 泛化表述如"教我 Python""我想学编程""Python 怎么写""帮我学 Python" 此 skill

下载
  • 提高性能:创建和销毁线程在资源方面是一项昂贵的操作。线程池通过重用现有线程来最小化此成本。

  • 资源管理:控制运行的线程数量,避免过多的线程创建导致系统过载。

  • 易于使用:简化线程管理,使开发人员能够专注于应用程序逻辑而不是线程管理。

  • 可扩展性:帮助扩展应用程序以有效地处理大量并发任务。

如何设置池中的线程限制

好吧,我当然必须创建一个线程池才能更好地利用此功能,但很快出现的一个问题是:“池应该包含多少个线程?”。按照基本逻辑,越多越好,对吗?如果所有事情都可以并行完成,那么很快就会完成,因为速度会更快。因此,最好不要限制线程数量,或者设置一个较高的数字,这样就不会出现问题。正确吗?
这是一个公平的说法,所以让我们测试一下。此测试的代码是用 kotlin 编写的,只是为了熟悉并易于编写示例。这一点与语言无关。
通过 4 个示例来探索不同的系统性质。示例 1 和示例 2 是为了使用 cpu 进行大量数学运算,即进行大量处理。示例3重点关注i/o,示例是读取文件,最后,示例4是并行api调用的情况,同样关注i/o。它们都使用不同大小的池,分别具有 1、2、4、8、16、32、50、100 和 500 个线程。所有过程发生超过 500 次。

示例 1 - 计算 1 到 100000 之间有多少个质数的代码

import kotlinx.coroutines.*
import kotlin.math.sqrt
import kotlin.system.measuretimemillis

fun isprime(number: int): boolean {
    if (number <= 1) return false
    for (i in 2..sqrt(number.todouble()).toint()) {
        if (number % i == 0) return false
    }
    return true
}

fun countprimesinrange(start: int, end: int): int {
    var count = 0
    for (i in start..end) {
        if (isprime(i)) {
            count++
        }
    }
    return count
}

@optin(delicatecoroutinesapi::class)
fun main() = runblocking {
    val rangestart = 1
    val rangeend = 100_000
    val numberofthreadslist = listof(1, 2, 4, 8, 16, 32, 50, 100, 500)

    for (numberofthreads in numberofthreadslist) {
        val customdispatcher = newfixedthreadpoolcontext(numberofthreads, "custompool")
        val chunksize = (rangeend - rangestart + 1) / numberofthreads
        val timetaken = measuretimemillis {
            val jobs = mutablelistof<deferred<int>>()
            for (i in 0 until numberofthreads) {
                val start = rangestart + i * chunksize
                val end = if (i == numberofthreads - 1) rangeend else start + chunksize - 1
                jobs.add(async(customdispatcher) { countprimesinrange(start, end) })
            }
            val totalprimes = jobs.awaitall().sum()
            println("total de números primos encontrados com $numberofthreads threads: $totalprimes")
        }
        println("tempo levado com $numberofthreads threads: $timetaken ms")
        customdispatcher.close()
    }
}
示例1 控制台输出
total de números primos encontrados com 1 threads: 9592
tempo levado com 1 threads: 42 ms
total de números primos encontrados com 2 threads: 9592
tempo levado com 2 threads: 17 ms
total de números primos encontrados com 4 threads: 9592
tempo levado com 4 threads: 8 ms
total de números primos encontrados com 8 threads: 9592
tempo levado com 8 threads: 8 ms
total de números primos encontrados com 16 threads: 9592
tempo levado com 16 threads: 16 ms
total de números primos encontrados com 32 threads: 9592
tempo levado com 32 threads: 12 ms
total de números primos encontrados com 50 threads: 9592
tempo levado com 50 threads: 19 ms
total de números primos encontrados com 100 threads: 9592
tempo levado com 100 threads: 36 ms
total de números primos encontrados com 500 threads: 9592
tempo levado com 500 threads: 148 ms

示例 2 - 计算斐波那契数列上第 30 个数字的代码

import kotlinx.coroutines.delicatecoroutinesapi
import kotlinx.coroutines.launch
import kotlinx.coroutines.newfixedthreadpoolcontext
import kotlinx.coroutines.runblocking
import kotlin.system.measuretimemillis

fun fibonacci(n: int): long {
    return if (n <= 1) n.tolong() else fibonacci(n - 1) + fibonacci(n - 2)
}

@optin(delicatecoroutinesapi::class)
fun main() = runblocking {
    val numberofthreadslist = listof(1, 2, 4, 8, 16, 32, 50, 100, 500)

    for (numberofthreads in numberofthreadslist) {
        val customdispatcher = newfixedthreadpoolcontext(numberofthreads, "custompool")
        val numberstocalculate = mutablelistof<int>()
        for (i in 1..1000) {
            numberstocalculate.add(30)
        }
        val timetaken = measuretimemillis {
            val jobs = numberstocalculate.map { number ->
                launch(customdispatcher) {
                    fibonacci(number)
                }
            }
            jobs.foreach { it.join() }
        }
        println("tempo levado com $numberofthreads threads: $timetaken ms")
        customdispatcher.close()
    }
}
示例2 控制台输出
tempo levado com 1 threads: 4884 ms
tempo levado com 2 threads: 2910 ms
tempo levado com 4 threads: 1660 ms
tempo levado com 8 threads: 1204 ms
tempo levado com 16 threads: 1279 ms
tempo levado com 32 threads: 1260 ms
tempo levado com 50 threads: 1364 ms
tempo levado com 100 threads: 1400 ms
tempo levado com 500 threads: 1475 ms

示例 3 - 读取随机数文件并在读取结束时添加它们的代码

import kotlinx.coroutines.*
import java.io.file
import kotlin.system.measuretimemillis

@optin(delicatecoroutinesapi::class)
fun main() = runblocking {
    val file = file("numeros_aleatorios.txt")

    if (!file.exists()) {
        println("arquivo não encontrado!")
        return@runblocking
    }
    val numberofthreadslist = listof(1, 2, 4, 8, 16, 32, 50, 100, 500)
    for (numberofthreads in numberofthreadslist) {
        val customdispatcher = newfixedthreadpoolcontext(numberofthreads, "custompool")
        val timetaken = measuretimemillis {
            val jobs = mutablelistof<deferred<int>>()
            file.uselines { lines ->
                lines.foreach { line ->
                    jobs.add(async(customdispatcher) {
                        processline(line)
                    })
                }
            }
            val totalsum = jobs.awaitall().sum()
            println("total da soma com $numberofthreads threads: $totalsum")
        }
        println("tempo levado com $numberofthreads threads: $timetaken ms")
        customdispatcher.close()
    }

}

fun processline(line: string): int {
    return line.toint() + 10
}
示例3 控制台输出
total da soma de 1201 linhas com 1 threads: 60192
tempo levado com 1 threads: 97 ms
total da soma de 1201 linhas com 2 threads: 60192
tempo levado com 2 threads: 28 ms
total da soma de 1201 linhas com 4 threads: 60192
tempo levado com 4 threads: 30 ms
total da soma de 1201 linhas com 8 threads: 60192
tempo levado com 8 threads: 26 ms
total da soma de 1201 linhas com 16 threads: 60192
tempo levado com 16 threads: 33 ms
total da soma de 1201 linhas com 32 threads: 60192
tempo levado com 32 threads: 35 ms
total da soma de 1201 linhas com 50 threads: 60192
tempo levado com 50 threads: 44 ms
total da soma de 1201 linhas com 100 threads: 60192
tempo levado com 100 threads: 66 ms
total da soma de 1201 linhas com 500 threads: 60192
tempo levado com 500 threads: 297 ms

示例 4 - 调用 api 500 次的代码

import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.request.*
import kotlinx.coroutines.delicatecoroutinesapi
import kotlinx.coroutines.launch
import kotlinx.coroutines.newfixedthreadpoolcontext
import kotlinx.coroutines.runblocking
import kotlin.system.measuretimemillis

@optin(delicatecoroutinesapi::class)
fun main() = runblocking {
    val client = httpclient(cio)

    try {
        val numberofthreadslist = listof(1, 2, 4, 8, 16, 32, 50, 100, 500)
        for (numberofthreads in numberofthreadslist) {
            val customdispatcher = newfixedthreadpoolcontext(numberofthreads, "custompool")
            val timetaken = measuretimemillis {
                repeat(500) {
                    val jobs = launch(customdispatcher) { client.get("http://127.0.0.1:5000/example") }
                    jobs.join()
                }
            }
            println("tempo levado com $numberofthreads threads: $timetaken ms")
            customdispatcher.close()
        }
    } catch (e: exception) {
        println("erro ao conectar à api: ${e.message}")
    } finally {
        client.close()
    }
}
示例4 控制台输出
Tempo levado com 1 threads: 7104 ms
Tempo levado com 2 threads: 4793 ms
Tempo levado com 4 threads: 4170 ms
Tempo levado com 8 threads: 4310 ms
Tempo levado com 16 threads: 4028 ms
Tempo levado com 32 threads: 4089 ms
Tempo levado com 50 threads: 4066 ms
Tempo levado com 100 threads: 3978 ms
Tempo levado com 500 threads: 3777 ms

示例 1 到示例 3 有一个共同的行为,它们在达到 8 个线程时性能都变得更高,然后处理时间再次增加,但示例 4 却没有,这说明了什么?总是使用尽可能多的线程不是很有趣吗?

简单而快速的答案是不。

我的机器的处理器有 8 个核心,也就是说,它可以同时执行 8 个任务,超过这个时间会随着管理每个线程状态的时间而增加,最终导致性能下降。

好的,这回答了示例 1 到 3,但是示例 4 呢?为什么启动的线程越多性能就会提高?

简单,因为它是一个集成,机器没有处理,它基本上等待响应,它保持“睡眠”直到响应到达,所以是的,这里线程的数量可以更大。但要小心,并不意味着可以有尽可能多的线程,线程会导致资源耗尽,不加区别地使用它们会产生相反的效果,会影响服务的整体健康状况。
因此,要定义池将拥有的线程数,最简单、最安全的方法是分离将要执行的任务的性质。它们分为两部分:

  • 不需要处理的任务:
    当任务类型不需要处理时,可以创建比机器上的处理器核心更多的线程。发生这种情况是因为不需要处理信息来完成线程,基本上这种性质的线程在大多数情况下都期望来自集成的响应,例如写入数据库或来自 api 的响应。

  • 需要处理的任务:
    当解决方案有处理时,即机器实际在做工作时,最大线程数必须是机器处理器的核心数。这是因为处理器核心无法同时执行多于一件事。例如,如果运行该解决方案的处理器有 4 个核心,那么它的线程池必须是您的处理器核心的大小,即 4 线程池。

结论

在考虑线程池时,首先要定义的一点不一定是限制其大小的数量,而是所执行任务的性质。线程对服务的性能有很大帮助,但必须以最佳方式使用它们,以免产生相反的效果并降低性能,甚至更糟糕的是,导致整个服务的健康状况受到影响。很明显,较小的池最终更倾向于处理大量使用的任务,换句话说,即 cpu 受限的任务。如果您不确定使用线程的解决方案是否具有大量使用处理的行为,请谨慎起见,将您的池限制为机器上的处理器数量,相信我,这会节省让你很头疼。

相关文章

数码产品性能查询
数码产品性能查询

该软件包括了市面上所有手机CPU,手机跑分情况,电脑CPU,电脑产品信息等等,方便需要大家查阅数码产品最新情况,了解产品特性,能够进行对比选择最具性价比的商品。

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

Seko
Seko Hot

一款AI视频创作工具,主要用于商汤科技推出的创编一体的AI短视频创作Agent,适合需要提升相关任务效率的用户。

PixPix
PixPix Hot

PixPix是一款面向电商视觉生产的AI商品图生成工具。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

Loomy
Loomy Hot

一款AI工具,主要用于科大讯飞发布的桌面级 AI 助理,比 OpenClaw 更易用、更安全!,适合需要提升相关任务效率的用户。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

切问学术

切问学术是一款AI论文写作工具,复旦大学NLP团队推出的AI学术智能体。

SkildArt
SkildArt Hot

SkildArt是一款AI文本写作工具,一站式 AI 视觉创作平台。

相关专题

更多
Kotlin协程编程与Spring Boot集成实践
Kotlin协程编程与Spring Boot集成实践

本专题围绕 Kotlin 协程机制展开,深入讲解挂起函数、协程作用域、结构化并发与异常处理机制,并结合 Spring Boot 展示协程在后端开发中的实际应用。内容涵盖异步接口设计、数据库调用优化、线程资源管理以及性能调优策略,帮助开发者构建更加简洁高效的 Kotlin 后端服务架构。

371

2026.02.12

Java Kotlin协程与异步编程实战
Java Kotlin协程与异步编程实战

本专题围绕 Kotlin 协程与异步编程展开,讲解挂起函数、协程作用域、异步任务调度及并发控制方法。通过实际项目案例,帮助开发者提升后端服务性能,实现高效异步任务处理与稳定性保障。

179

2026.04.13

Kotlin Android开发教程大全
Kotlin Android开发教程大全

系统讲解 Google 官方推荐的 Android 开发首选语言 Kotlin 的核心知识与工程实践,涵盖 Kotlin 简洁语法(空安全/数据类/扩展函数/解构声明/作用域函数)与 Java 互操作、集合操作与函数式编程、协程(Coroutines)异步编程(suspend/launch/async/Flow)、Jetpack Compose 声明式 UI 开发(状态管理/组合函数/导航/动画)、MVVM / MVI 架构设计与 Vi

268

2026.06.03

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

4338

2023.08.10

数据库三范式
数据库三范式

数据库三范式是一种设计规范,用于规范化关系型数据库中的数据结构,它通过消除冗余数据、提高数据库性能和数据一致性,提供了一种有效的数据库设计方法。本专题提供数据库三范式相关的文章、下载和课程。

2825

2023.06.29

如何删除数据库
如何删除数据库

删除数据库是指在MySQL中完全移除一个数据库及其所包含的所有数据和结构,作用包括:1、释放存储空间;2、确保数据的安全性;3、提高数据库的整体性能,加速查询和操作的执行速度。尽管删除数据库具有一些好处,但在执行任何删除操作之前,务必谨慎操作,并备份重要的数据。删除数据库将永久性地删除所有相关数据和结构,无法回滚。

4001

2023.08.14

vb怎么连接数据库
vb怎么连接数据库

在VB中,连接数据库通常使用ADO(ActiveX 数据对象)或 DAO(Data Access Objects)这两个技术来实现:1、引入ADO库;2、创建ADO连接对象;3、配置连接字符串;4、打开连接;5、执行SQL语句;6、处理查询结果;7、关闭连接即可。

3151

2023.08.31

MySQL恢复数据库
MySQL恢复数据库

MySQL恢复数据库的方法有使用物理备份恢复、使用逻辑备份恢复、使用二进制日志恢复和使用数据库复制进行恢复等。本专题为大家提供MySQL数据库相关的文章、下载、课程内容,供大家免费下载体验。

987

2023.09.05

Gradle插件开发入门教程
Gradle插件开发入门教程

本专题介绍Gradle插件开发的基本流程,涵盖插件类编写、自定义任务注册、扩展参数设计和插件应用方法,帮助你理解插件如何组织构建逻辑,减少多个项目之间的重复配置。

40

2026.10.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Uvicorn官方安装与入门手册
Uvicorn官方安装与入门手册

共0课时 | 0人学习

Python uv官方项目管理指南
Python uv官方项目管理指南

共0课时 | 0人学习

Python uv官方安装与入门文档
Python uv官方安装与入门文档

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn