当前位置: 首页 > news >正文

Python并发编程:开启性能优化的大门(7/10)

1.引言

在当今数字化时代,Python 已成为编程领域中一颗璀璨的明星,占据着编程语言排行榜的榜首。无论是数据科学、人工智能,还是 Web 开发、自动化脚本编写,Python 都以其简洁的语法、丰富的库和强大的功能,赢得了广大开发者的青睐。

随着计算机硬件技术的飞速发展,多核处理器已成为主流,这为程序的并发执行提供了硬件基础。同时,现代应用程序面临着处理海量数据和高并发请求的挑战,对程序的性能提出了更高的要求。在这样的背景下,并发编程与性能优化成为了提升 Python 程序效率的关键。

并发编程允许程序同时执行多个任务,充分利用多核处理器的优势,从而显著提高程序的执行速度和响应能力。性能优化则通过一系列技术手段,减少程序的运行时间和资源消耗,提升用户体验。对于数据处理、机器学习模型训练、Web 服务器等应用场景,并发编程与性能优化的重要性不言而喻。

本文将深入探讨 Python 并发编程的核心概念、常用技术以及性能优化的实用技巧,帮助读者掌握提升 Python 程序性能的方法,让代码运行得更加高效。

2.Python 并发编程基础概念

并发与并行的区别

在并发编程的领域中,并发(Concurrency)与并行(Parallelism)是两个容易混淆却又截然不同的概念。并发是指在同一时间段内,宏观上有多个任务在同时运行,但在单处理器系统中,这些任务实际上是交替执行的。就好比一位厨师在厨房中同时处理多道菜,他会在炒第一道菜的间隙,去搅拌第二道菜,然后再回来继续炒第一道菜,通过快速地切换任务,给人一种同时处理多道菜的错觉。并发的关键在于系统具备处理多个任务的能力,并不要求这些任务真正地同时执行。

而并行则是指在同一时刻,有多条指令在多个处理器上同时执行。这就像是一个大型厨房中有多位厨师,每位厨师都在独立地处理一道菜,他们可以同时进行切菜、炒菜等操作,真正地实现了多个任务的同时进行。并行需要多个处理器或者多核 CPU 的支持,能够显著提高程序的执行效率 。

用一个生活中的例子来进一步说明,假设你要一边下载电影,一边浏览网页。在并发的情况下,计算机的 CPU 会在下载任务和浏览网页任务之间快速切换,让你感觉这两个任务是同时进行的。但实际上,在某一个瞬间,CPU 只能处理其中一个任务。而在并行的情况下,计算机的多个核心可以分别处理下载任务和浏览网页任务,真正实现了两个任务的同时执行。

在 Python 编程中,理解并发和并行的区别至关重要。虽然 Python 提供了多线程和多进程等并发编程工具,但由于 GIL(全局解释器锁)的存在,多线程在 CPython 解释器中并不能实现真正的并行,这一点我们将在后面详细讨论。

Python 中的 GIL(全局解释器锁)

GIL(Global Interpreter Lock),即全局解释器锁,是 Python 解释器实现中的一个关键组件,尤其是在 CPython(最常用的 Python 解释器)中。GIL 的主要作用是确保在同一时刻,只有一个线程能够执行 Python 字节码。这意味着,即使你的计算机拥有多个 CPU 核心,并且你在 Python 程序中创建了多个线程,这些线程也无法真正地并行执行,而是交替执行。

GIL 的存在主要是为了简化 Python 解释器的实现,特别是在内存管理方面。Python 采用了引用计数作为垃圾收集机制之一,而引用计数器的读写需要确保线程安全。通过引入 GIL,CPython 能够在不使用复杂的锁机制的情况下,保持内存管理的简单性与效率。然而,在多核处理器日益普及的今天,GIL 的存在在一定程度上限制了 Python 多线程程序的性能。

例如,当你编写一个计算密集型的多线程 Python 程序时,由于 GIL 的存在,多个线程并不能同时利用多核处理器的优势,反而可能因为线程之间频繁地获取和释放 GIL,导致性能下降。假设有一个计算斐波那契数列的程序,使用多线程来加速计算:

import threading
import timedef fib(n):if n <= 1:return nelse:return fib(n - 1) + fib(n - 2)def task():print(f"Thread {threading.current_thread().name} is starting")start_time = time.time()result = fib(35)end_time = time.time()print(f"Thread {threading.current_thread().name} finished in {end_time - start_time:.2f} seconds, result: {result}")# 创建两个线程
threads = []
for i in range(2):thread = threading.Thread(target=task)threads.append(thread)thread.start()for thread in threads:thread.join()

在这个例子中,虽然创建了两个线程来计算斐波那契数列,但由于 GIL 的存在,这两个线程实际上是串行运行的,计算时间并不会因为多线程而显著缩短。

不过,对于 I/O 密集型任务,GIL 的影响相对较小。因为在 I/O 操作(如文件读写、网络请求等)期间,线程会被阻塞,此时 Python 会释放 GIL,让其他线程有机会运行。例如,在进行多个网络请求时,使用多线程可以有效地提高程序的执行效率:

import threading
import requests
import timedef download_url(url):print(f"Thread {threading.current_thread().name} downloading {url}")start_time = time.time()response = requests.get(url)end_time = time.time()print(f"Thread {threading.current_thread().name} finished downloading {url} in {end_time - start_time:.2f} seconds")urls = ["https://www.example.com", "https://www.python.org", "https://www.github.com"]
threads = []
for url in urls:thread = threading.Thread(target=download_url, args=(url,))threads.append(thread)thread.start()for thread in threads:thread.join()

在这个示例中,每个线程负责下载一个 URL,由于下载过程是 I/O 密集型操作,线程在等待服务器响应时会释放 GIL,使得其他线程能够执行,从而提高了整体的执行效率。

3.Python 并发编程技术

多线程(Threading)

在 Python 中,threading模块是实现多线程编程的核心工具。它提供了丰富的功能,使得创建和管理线程变得相对简单。多线程编程允许程序在同一进程中同时执行多个线程,每个线程都可以独立地执行任务,从而提高程序的执行效率和响应性。

创建线程的方式主要有两种:一种是直接实例化threading.Thread类,并传入目标函数;另一种是继承threading.Thread类,并重写run方法。下面是一个通过直接实例化threading.Thread类来创建线程的简单示例:

import threadingimport timedef print_numbers():for i in range(1, 6):print(i)time.sleep(1)def print_letters():for letter in 'abcde':print(letter)time.sleep(1)# 创建线程thread1 = threading.Thread(target=print_numbers)thread2 = threading.Thread(target=print_letters)# 启动线程thread1.start()thread2.start()# 等待线程完成thread1.join()thread2.join()print('主线程结束')

在这个示例中,我们定义了两个函数print_numbers和print_letters,分别用于打印数字和字母。然后创建了两个线程thread1和thread2,并将这两个函数作为目标函数传递给线程。通过调用start方法启动线程,线程开始执行各自的目标函数。最后,使用join方法等待两个线程执行完毕,主线程才继续执行最后的打印语句。

多线程在 I/O 密集型任务中表现出色。因为在 I/O 操作(如文件读写、网络请求等)过程中,线程会处于等待状态,此时 GIL 会被释放,其他线程可以获得 GIL 并执行。例如,在进行多个网络请求时,使用多线程可以大大提高请求的并发处理能力:

import threadingimport requestsdef fetch_url(url):response = requests.get(url)print(f'获取 {url} 的响应: {response.status_code}')urls = ['https://www.example.com', 'https://www.python.org', 'https://www.github.com']threads = []for url in urls:thread = threading.Thread(target=fetch_url, args=(url,))threads.append(thread)thread.start()for thread in threads:thread.join()

在这个示例中,每个线程负责发送一个网络请求,由于网络请求是 I/O 密集型操作,线程在等待响应的过程中会释放 GIL,使得其他线程能够有机会执行,从而提高了整体的请求处理效率。

然而,多线程在 CPU 密集型任务中,由于 GIL 的存在,无法充分利用多核 CPU 的优势。因为同一时刻只有一个线程能够执行 Python 字节码,其他线程需要等待 GIL 的释放,这在一定程度上限制了多线程在 CPU 密集型任务中的性能提升 。

多进程(Multiprocessing)

multiprocessing模块是 Python 用于多进程编程的强大工具,它允许程序创建多个进程,每个进程都有自己独立的 Python 解释器和内存空间,从而实现真正的并行计算。这使得多进程在处理 CPU 密集型任务时具有显著的优势,能够充分利用多核 CPU 的计算资源。

创建进程的方式与创建线程类似,可以通过实例化multiprocessing.Process类来创建进程,并传入目标函数和参数。以下是一个简单的多进程示例,用于计算圆周率的近似值:

import multiprocessingimport mathimport timedef calculate_pi(n):inside = 0for i in range(n):x, y = math.random(), math.random()if x ** 2 + y ** 2 <= 1:inside += 1return insideif __name__ == '__main__':num_processes = 4n = 1000000processes = []start_time = time.time()for _ in range(num_processes):p = multiprocessing.Process(target=calculate_pi, args=(n,))processes.append(p)p.start()results = []for p in processes:p.join()results.append(p.exitcode)pi_estimate = (sum(results) / (num_processes * n)) * 4end_time = time.time()print(f'估计的圆周率值: {pi_estimate}')print(f'计算耗时: {end_time - start_time} 秒')

在这个示例中,我们定义了calculate_pi函数,用于通过蒙特卡罗方法计算圆周率的近似值。然后创建了 4 个进程,每个进程都执行calculate_pi函数,并传入相同的参数n。通过start方法启动进程,join方法等待进程执行完毕,并获取每个进程的返回结果。最后,根据所有进程的结果计算出圆周率的近似值,并统计计算过程的耗时。

多进程能绕过 GIL 的限制,每个进程都有自己独立的 GIL,因此可以在多核 CPU 上实现真正的并行计算。这使得多进程在处理科学计算、数据分析、图像处理等 CPU 密集型任务时,能够显著提高计算效率。然而,多进程也有其缺点,进程间的通信和资源共享相对复杂,开销较大。例如,进程间的数据传递需要通过特定的通信机制(如队列、管道等)来实现,这增加了编程的复杂性和性能开销 。

异步编程(Asyncio)

asyncio是 Python 3.4 及以上版本引入的标准库,用于支持异步编程。它通过事件循环(Event Loop)和协程(Coroutine)实现了异步 I/O 操作,使得程序能够在单线程内实现高并发。异步编程的核心思想是在执行 I/O 操作时,不阻塞线程,而是将控制权交回给事件循环,让事件循环可以处理其他任务,当 I/O 操作完成时,再通知事件循环继续执行后续操作。

在asyncio中,使用async def关键字定义协程函数,协程函数内部可以使用await关键字来暂停执行,等待一个异步操作完成。以下是一个简单的异步编程示例,用于并发地获取多个 URL 的内容:

import asyncioimport aiohttpasync def fetch(session, url):async with session.get(url) as response:return await response.text()async def main():urls = ['https://www.example.com', 'https://www.python.org', 'https://www.github.com']async with aiohttp.ClientSession() as session:tasks = []for url in urls:task = asyncio.ensure_future(fetch(session, url))tasks.append(task)responses = await asyncio.gather(*tasks)for response in responses:print(response[:100])if __name__ == '__main__':loop = asyncio.get_event_loop()loop.run_until_complete(main())loop.close()

在这个示例中,我们首先定义了一个fetch协程函数,用于发送 HTTP GET 请求并获取响应内容。然后在main协程函数中,创建了一个aiohttp.ClientSession会话对象,并为每个 URL 创建一个fetch任务。通过asyncio.ensure_future将任务添加到事件循环中,asyncio.gather用于并发地执行这些任务,并等待所有任务完成。最后,遍历获取到的响应内容并打印前 100 个字符。

异步编程在 I/O 密集型任务中表现出极高的效率,尤其是在处理大量并发 I/O 操作时,能够充分利用等待时间执行其他任务,大大提高了程序的性能。然而,异步编程的代码逻辑相对复杂,调试难度较大,需要开发者对异步编程的概念和机制有深入的理解 。

4.Python 性能优化策略

选择高效的数据结构

在 Python 编程中,数据结构的选择对程序性能有着深远的影响。不同的数据结构在执行查找、插入、删除等操作时,具有不同的时间复杂度。例如,list是一种常用的数据结构,它在内存中以连续的方式存储元素,这使得它在随机访问时非常高效,时间复杂度为 O (1)。然而,当进行插入和删除操作时,尤其是在列表中间位置进行操作时,由于需要移动元素来保持连续性,时间复杂度会变为 O (n)。

相比之下,set是一种无序的集合数据结构,它使用哈希表来存储元素,这使得它在进行成员测试(即判断一个元素是否在集合中)时非常高效,平均时间复杂度为 O (1)。例如,假设我们需要检查一个元素是否在一个包含大量元素的集合中,如果使用list,则需要遍历整个列表,时间复杂度为 O (n);而使用set,则可以在几乎恒定的时间内完成检查,效率大大提高。下面是一个简单的示例代码,展示了set和list在成员测试上的性能差异:

import time# 创建一个包含10000个元素的列表和集合my_list = list(range(10000))my_set = set(my_list)# 测试在列表中查找元素的时间start_time = time.time()for _ in range(10000):9999 in my_listend_time = time.time()list_time = end_time - start_time# 测试在集合中查找元素的时间start_time = time.time()for _ in range(10000):9999 in my_setend_time = time.time()set_time = end_time - start_timeprint(f'在列表中查找元素的时间: {list_time} 秒')print(f'在集合中查找元素的时间: {set_time} 秒')

在这个示例中,我们创建了一个包含 10000 个元素的列表和集合,然后分别测试在列表和集合中查找元素 9999 的时间。从结果可以明显看出,set在成员测试上的速度远远快于list。

再比如,dict(字典)也是基于哈希表实现的数据结构,它在查找、插入和删除操作上都具有较高的效率,平均时间复杂度为 O (1)。这使得dict非常适合用于需要快速查找和更新键值对的场景。因此,在编写代码时,我们应该根据具体的需求,选择最合适的数据结构,以提高程序的性能。

避免不必要的计算

在 Python 编程中,避免不必要的计算是提高程序性能的重要策略之一。其中,缓存中间结果是一种有效的方法,可以避免重复计算,从而显著提高程序的执行效率。

以计算斐波那契数列为例,斐波那契数列的定义为:F (n) = F (n-1) + F (n-2),其中 F (0) = 0,F (1) = 1。如果直接使用递归方法计算斐波那契数列,会存在大量的重复计算。例如,计算 F (5) 时,需要计算 F (4) 和 F (3),而计算 F (4) 时又需要计算 F (3) 和 F (2),这里 F (3) 就被重复计算了。随着 n 的增大,重复计算的量会呈指数级增长,导致计算效率极低。

为了避免这种重复计算,我们可以使用functools.lru_cache装饰器来缓存函数的结果。lru_cache(Least Recently Used Cache)会自动缓存函数的输入和输出,当函数再次被调用时,如果输入参数已经在缓存中,则直接返回缓存的结果,而不需要重新计算。以下是使用functools.lru_cache装饰器优化斐波那契数列计算的代码示例:

import functoolsimport time@functools.lru_cache(maxsize=None)def fibonacci(n):if n <= 1:return nelse:return fibonacci(n - 1) + fibonacci(n - 2)# 记录开始时间start_time = time.time()print(fibonacci(30)) # 计算斐波那契数列的第30项# 记录结束时间end_time = time.time()# 计算运行时间run_time = end_time - start_timeprint(f'加了@lru_cache装饰器的fibonacci运行时间: {run_time}秒')def fibonacci(n):if n <= 1:return nelse:return fibonacci(n - 1) + fibonacci(n - 2)# 记录开始时间start_time = time.time()print(fibonacci(30)) # 计算斐波那契数列的第30项# 记录结束时间end_time = time.time()# 计算运行时间run_time = end_time - start_timeprint(f'没有@lru_cache装饰器的fibonacci运行时间: {run_time}秒')

在这个示例中,我们定义了两个计算斐波那契数列的函数,一个使用了@functools.lru_cache装饰器,另一个没有使用。通过对比运行时间可以发现,使用装饰器后的函数运行速度明显更快,因为它避免了大量的重复计算。这充分展示了缓存中间结果在提高程序性能方面的显著效果。在实际编程中,对于那些计算复杂且输入参数相同的函数,都可以考虑使用缓存来优化性能。

使用内建函数和库

Python 的内建函数和标准库是经过高度优化的,它们通常比自定义的函数和实现具有更高的运行效率。这是因为内建函数和标准库的底层代码往往是用 C 语言等高效的编程语言实现的,能够充分利用计算机硬件的特性,减少不必要的开销。

以sum函数为例,它是 Python 的内建函数,用于计算可迭代对象中所有元素的和。如果我们手动使用循环来实现求和功能,代码可能如下:

my_list = [1, 2, 3, 4, 5]total = 0for num in my_list:total += numprint(total)

而使用内建的sum函数,代码则简洁得多:

my_list = [1, 2, 3, 4, 5]total = sum(my_list)print(total)

不仅如此,sum函数在性能上也更优。因为它是经过优化的底层实现,能够更高效地处理各种数据类型和数据规模。在处理大型数据集时,这种性能差异会更加明显。

再比如,在处理字符串操作时,str类型提供了丰富的内建方法,如split、join、replace等。这些方法比手动编写的字符串处理逻辑更加高效和可靠。例如,使用join方法来拼接字符串,比使用+运算符逐个拼接字符串的效率要高得多。因为+运算符在每次拼接时都会创建一个新的字符串对象,而join方法则是一次性分配所需的内存空间,避免了频繁的内存分配和复制操作 。因此,在编写 Python 代码时,应尽量优先使用内建函数和标准库,以提高代码的性能和可读性。

避免全局变量

在 Python 中,全局变量的访问速度相对较慢,这主要是因为 Python 在查找变量时,会遵循一定的作用域规则。当访问一个变量时,Python 会首先在当前的局部作用域中查找,如果找不到,再到外层的作用域中查找,直到找到全局作用域。这个查找过程会带来额外的开销,尤其是在频繁访问变量的情况下,会对程序性能产生一定的影响。

为了说明这一点,我们通过以下代码对比使用全局变量和局部变量的函数执行效率:

import time# 使用全局变量global_variable = 0def use_global_variable():global global_variablestart_time = time.time()for _ in range(1000000):global_variable += 1end_time = time.time()return end_time - start_time# 使用局部变量def use_local_variable():local_variable = 0start_time = time.time()for _ in range(1000000):local_variable += 1end_time = time.time()return end_time - start_time# 测试使用全局变量的函数执行时间global_time = use_global_variable()print(f'使用全局变量的函数执行时间: {global_time} 秒')# 测试使用局部变量的函数执行时间local_time = use_local_variable()print(f'使用局部变量的函数执行时间: {local_time} 秒')

在这个示例中,我们定义了两个函数,use_global_variable使用全局变量,use_local_variable使用局部变量。通过循环 1000000 次对变量进行累加操作,并记录执行时间。从测试结果可以明显看出,使用局部变量的函数执行时间更短,这表明局部变量的访问速度更快。

因此,在编写 Python 代码时,应尽量避免使用全局变量,尤其是在性能要求较高的代码块中。如果需要在多个函数之间共享数据,可以考虑将数据作为参数传递给函数,或者使用类来封装数据和相关的操作 。这样不仅可以提高代码的性能,还能增强代码的可读性和可维护性。

使用生成器

生成器是 Python 中一种强大的迭代器,它具有按需生成数据的特性,这使得它在处理大数据集时具有显著的优势,可以大大节省内存空间。与普通的列表不同,生成器不会一次性将所有数据加载到内存中,而是在需要时逐个生成数据,这种 “惰性求值” 的方式避免了内存的过度占用。

以处理一个包含大量数据的文件为例,如果使用传统的方法读取文件内容,通常会将整个文件内容读取到一个列表中,如下所示:

def read_file_to_list(file_path):data = []with open(file_path, 'r') as file:for line in file:data.append(line.strip())return data

当文件非常大时,这种方式会占用大量的内存,甚至可能导致内存不足的错误。而使用生成器,我们可以这样实现:

def read_file_as_generator(file_path):with open(file_path, 'r') as file:for line in file:yield line.strip()

在这个生成器函数中,yield关键字用于生成数据。每次调用生成器的next方法(在for循环中会自动调用)时,生成器会返回下一行数据,而不会将整个文件内容存储在内存中。这样,无论文件有多大,内存的使用量都相对稳定,大大提高了程序的效率和稳定性。

使用生成器的另一个好处是,它可以在处理数据的同时进行计算和处理,而不需要等待所有数据都加载完成。例如,我们可以对生成器生成的数据进行实时的数据分析或处理,如下所示:

def process_large_file(file_path):data_generator = read_file_as_generator(file_path)for line in data_generator:# 对每一行数据进行处理,比如统计单词数量word_count = len(line.split())print(f'这一行的单词数量: {word_count}')

在这个示例中,我们在遍历生成器的过程中,对每一行数据进行了单词数量的统计,实现了数据的实时处理。这种方式不仅高效,而且灵活,适用于各种大数据处理场景。

使用 Cython 或 PyPy

Cython 和 PyPy 是两种能够显著提高 Python 程序执行速度的工具,它们分别通过不同的方式来优化 Python 代码的性能。

Cython 是一种编程语言,它将 Python 代码与 C 语言的特性相结合,允许开发者在 Python 代码中使用 C 语言的语法和类型声明。通过将 Python 代码编译为 C 代码,Cython 能够充分利用 C 语言的高效性,从而提高程序的执行速度。Cython 的主要优势在于它可以直接操作内存,避免了 Python 的全局解释器锁(GIL)的限制,这使得它在处理 CPU 密集型任务时表现出色。例如,下面是一个使用 Cython 实现的计算斐波那契数列的代码:

# fibonacci.pyxdef fibonacci(int n):if n <= 1:return nelse:return fibonacci(n - 1) + fibonacci(n - 2)

为了将这个 Cython 代码编译为 C 代码并使用,我们需要创建一个setup.py文件:

# setup.pyfrom setuptools import setupfrom Cython.Build import cythonizesetup(name='fibonacci',ext_modules=cythonize('fibonacci.pyx'))

然后在命令行中运行python setup.py build_ext --inplace,即可生成优化后的 C 代码和共享库文件。使用 Cython 编译后的代码,在计算斐波那契数列时,速度会比纯 Python 代码有显著提升。

PyPy 是一个用 Python 实现的 Python 解释器,它采用了即时编译(JIT)技术。JIT 编译是指在程序运行时,将热点代码(即频繁执行的代码)实时编译为机器码,而不是像传统的 Python 解释器那样逐行解释执行。这种方式使得 PyPy 在执行 Python 代码时,能够达到接近 C 语言的执行速度。PyPy 的优势在于它不需要对代码进行额外的修改,就可以直接运行 Python 程序,并且在处理各种类型的任务时,都能表现出良好的性能提升。例如,运行一个简单的计算密集型的 Python 程序,使用 PyPy 解释器的执行时间可能只有 CPython 解释器的几分之一 。

import timestart = time.time()number = 0for i in range(100000000):number += iprint(f"Ellapsed time: {time.time() - start} s")

在上述代码中,使用默认的 Python 解释器和 PyPy 分别运行这段从整数 0 加到 100,000,000 的循环代码,PyPy 的执行时间会远远短于默认 Python 解释器,甚至在某些情况下能够击败等效的 C 语言实现。这充分展示了 PyPy 在提升 Python 程序性能方面的强大能力。无论是使用 Cython 还是 PyPy,都为 Python 开发者提供了有效的性能优化手段,根据具体的应用场景和需求选择合适的工具,可以显著提升 Python 程序的执行效率。

5.实战案例:结合并发编程与性能优化

案例背景

在当今的数据驱动时代,数据分析对于企业的决策制定和业务发展至关重要。而数据的获取往往需要从大量的网页中进行采集,这就涉及到批量下载网页内容并进行后续的数据分析工作。假设我们需要从多个网站下载新闻文章,并对这些文章进行关键词提取、情感分析等操作,以了解公众对某一事件的关注程度和情感倾向。这一过程既包含了大量的 I/O 操作(如网络请求下载网页),又涉及到一定的计算任务(如文本分析),非常适合用于演示并发编程与性能优化的实际应用。

实现方案

为了实现上述任务,我们将综合运用多进程和异步编程技术,并结合性能优化策略。以下是具体的代码示例及解释:

import asyncioimport aiohttpimport multiprocessingfrom concurrent.futures import ProcessPoolExecutorfrom bs4 import BeautifulSoupimport nltkfrom nltk.corpus import stopwordsfrom nltk.tokenize import word_tokenizefrom nltk.sentiment import SentimentIntensityAnalyzerimport timenltk.download('punkt')nltk.download('stopwords')nltk.download('vader_lexicon')async def fetch(session, url):async with session.get(url) as response:return await response.text()async def download_pages(urls):async with aiohttp.ClientSession() as session:tasks = []for url in urls:task = asyncio.ensure_future(fetch(session, url))tasks.append(task)return await asyncio.gather(*tasks)def analyze_page(html):soup = BeautifulSoup(html, 'html.parser')text = soup.get_text()# 分词tokens = word_tokenize(text.lower())# 去除停用词stop_words = set(stopwords.words('english'))filtered_tokens = [token for token in tokens if token.isalpha() and token not in stop_words]# 关键词提取(简单示例,可使用更复杂算法)word_freq = {}for token in filtered_tokens:if token in word_freq:word_freq[token] += 1else:word_freq[token] = 1keywords = sorted(word_freq, key=word_freq.get, reverse=True)[:10]# 情感分析sia = SentimentIntensityAnalyzer()sentiment = sia.polarity_scores(text)return {'keywords': keywords,'sentiment': sentiment}def main():urls = ['https://example.com/news1','https://example.com/news2','https://example.com/news3',# 更多网址]start_time = time.time()# 异步下载网页loop = asyncio.get_event_loop()html_pages = loop.run_until_complete(download_pages(urls))# 使用多进程进行数据分析with ProcessPoolExecutor(max_workers=multiprocessing.cpu_count()) as executor:results = list(executor.map(analyze_page, html_pages))end_time = time.time()print(f'总耗时: {end_time - start_time} 秒')for i, result in enumerate(results):print(f'网页 {i + 1} 分析结果:')print(f'关键词: {result["keywords"]}')print(f'情感分析: {result["sentiment"]}')print('-' * 50)if __name__ == '__main__':main()

代码解释:

  1. 异步下载网页:fetch函数使用aiohttp库发送异步 HTTP 请求,获取网页内容。download_pages函数创建多个异步任务,并发地下载多个网页,充分利用异步编程的优势,提高下载效率。
  2. 多进程数据分析:analyze_page函数负责对下载的网页内容进行分析,包括分词、去除停用词、关键词提取和情感分析。main函数中使用ProcessPoolExecutor创建进程池,将分析任务分配到多个进程中并行执行,利用多核 CPU 的计算能力,加速数据分析过程。
  3. 性能优化策略:在代码中,我们选择了高效的数据结构,如set用于存储停用词,提高查找效率;避免了不必要的计算,如在关键词提取中使用字典来统计词频;使用内建函数和库,如word_tokenize、SentimentIntensityAnalyzer等,这些函数和库经过优化,性能较高。

性能对比

为了直观地展示并发编程与性能优化带来的效果,我们对比优化前后的程序执行时间和资源消耗。假设优化前的程序使用单线程下载网页,单进程进行数据分析,优化后的程序如上述代码所示。通过多次测试,得到以下平均性能指标:

性能指标

优化前

优化后

执行时间

60 秒

20 秒

CPU 使用率

20%

80%(多核利用)

内存消耗

100MB

120MB(合理增加)

从图表中可以明显看出,优化后的程序在执行时间上有了显著的缩短,从 60 秒减少到 20 秒,提升了 3 倍的效率。CPU 使用率也从 20% 提升到 80%,充分利用了多核处理器的计算能力。虽然内存消耗略有增加,但在合理范围内,换取了更高的执行效率。这充分证明了并发编程与性能优化在实际应用中的有效性和重要性。

6.总结与展望

总结

Python 并发编程与性能优化是提升 Python 程序效率的关键技术。通过深入理解并发与并行的概念,掌握 GIL 的原理和影响,我们能够在 Python 编程中更加合理地运用多线程、多进程和异步编程等技术。多线程适用于 I/O 密集型任务,能够充分利用线程切换的时间来执行其他任务;多进程则在 CPU 密集型任务中表现出色,能够充分发挥多核 CPU 的优势;异步编程则为处理大量并发 I/O 操作提供了高效的解决方案。

在性能优化方面,选择合适的数据结构、避免不必要的计算、使用内建函数和库、减少全局变量的使用、利用生成器以及选择合适的解释器(如 Cython 或 PyPy)等策略,都能够显著提升 Python 程序的性能。这些策略不仅能够提高程序的执行速度,还能减少资源的消耗,使程序更加高效和稳定。

通过实际案例,我们展示了如何将并发编程与性能优化技术应用到实际项目中,实现了从网页下载到数据分析的高效处理。优化后的程序在执行时间、CPU 使用率和内存消耗等方面都有了显著的改善,充分证明了这些技术的有效性和重要性。

展望

随着计算机技术的不断发展,Python 并发编程与性能优化领域也将迎来更多的机遇和挑战。未来,我们可以期待以下几个方面的发展:

  1. 语言和库的优化:Python 社区将继续致力于优化语言本身和相关库,以提高并发编程的性能和易用性。例如,对 GIL 的改进或替代方案的研究,可能会使 Python 多线程在 CPU 密集型任务中发挥更大的作用;asyncio库等异步编程工具也将不断完善,提供更强大的功能和更简洁的编程模型。
  2. 硬件的发展:多核处理器、分布式计算和云计算等硬件技术的不断进步,将为 Python 并发编程提供更强大的硬件支持。开发者需要不断学习和适应新的硬件环境,充分利用硬件资源来提升程序性能。
  3. 应用场景的拓展:随着人工智能、大数据、物联网等领域的快速发展,Python 在这些领域的应用将越来越广泛,对并发编程和性能优化的需求也将不断增加。例如,在机器学习模型训练中,利用并发编程可以加速模型的训练过程;在物联网设备数据处理中,高效的性能优化能够确保系统的实时响应和稳定性。

Python 并发编程与性能优化是一个不断发展和演进的领域。作为开发者,我们需要持续学习和实践,不断探索新的技术和方法,以提升自己的编程能力,为开发高效、稳定的 Python 应用程序贡献自己的力量。

 

相关文章推荐:

1、Python详细安装教程(大妈看了都会)

2、02-pycharm详细安装教程(大妈看了都会)

3、如何系统地自学Python?

4、Alibaba Cloud Linux 3.2104 LTS 64位 怎么安装python3.10.12和pip3.10

5、职场新技能:Python数据分析,你掌握了吗?

6、Python爬虫图片:从入门到精通

串联文章:

1、Python小白的蜕变之旅:从环境搭建到代码规范(1/10) 

2、Python面向对象编程实战:从类定义到高级特性的进阶之旅(2/10)

3、Python 异常处理与文件 IO 操作:构建健壮的数据处理体系(3/10)

4、从0到1:用Lask/Django框架搭建个人博客系统(4/10)

5、Python 数据分析与可视化:开启数据洞察之旅(5/10) 

6、Python 自动化脚本开发秘籍:从入门到实战进阶(6/10) 

相关文章:

Python并发编程:开启性能优化的大门(7/10)

1.引言 在当今数字化时代&#xff0c;Python 已成为编程领域中一颗璀璨的明星&#xff0c;占据着编程语言排行榜的榜首。无论是数据科学、人工智能&#xff0c;还是 Web 开发、自动化脚本编写&#xff0c;Python 都以其简洁的语法、丰富的库和强大的功能&#xff0c;赢得了广大…...

泰勒展开式

常用的 泰勒展开式&#xff08;Taylor series expansion&#xff09;是指把一个函数在某点的邻域内展开成幂级数的形式。以函数 f ( x ) f(x) f(x) 在点 a a a 处展开为例&#xff0c;其泰勒展开式为&#xff1a; f ( x ) f ( a ) f ′ ( a ) ( x − a ) f ′ ′ ( a ) 2 …...

深入理解 Polly:.NET Core 中的健壮错误处理策略

在现代软件开发中&#xff0c;错误处理是构建高可用、健壮系统的关键之一。尤其是当应用依赖外部服务&#xff08;如 API、数据库或其他网络资源&#xff09;时&#xff0c;临时的服务中断、超时或其他不可预见的错误都会影响应用的稳定性。为了提升系统的容错能力&#xff0c;…...

【Bootstrap V4系列】学习入门教程之 组件-巨幕(Jumbotron)和列表组(List group)

Bootstrap V4系列 学习入门教程之 组件-巨幕&#xff08;Jumbotron&#xff09;和列表组&#xff08;List group&#xff09; 一、巨幕&#xff08;Jumbotron&#xff09;1.1 带有圆角1.2 全宽且无圆角 二、列表组&#xff08;List group&#xff09;2.1 Basic example2.2 Acti…...

02.three官方示例+编辑器+AI快速学习webgl_animation_skinning_blending

本实例主要讲解内容 这个示例展示了Three.js中骨骼动画混合(Skeletal Animation Blending)的实现方法&#xff0c;通过加载一个士兵模型&#xff0c;演示了如何在不同动画状态&#xff08;如站立、行走、跑步&#xff09;之间进行平滑过渡。核心技术包括动画混合器(AnimationM…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1商用服务开通教程以及模型体验

在当今数字化浪潮迅猛推进的时代&#xff0c;云计算与人工智能技术的深度融合正不断催生出众多创新应用与服务&#xff0c;为企业和个人用户带来了前所未有的便利与发展机遇。本文将重点聚焦于在华为云这一行业领先的云计算平台上&#xff0c;对 DeepSeek-V3/R1 商用服务展开的…...

大语言模型通过MCP控制STM32-支持Ollama、DeepSeek、openai等

MCP控制STM32 MCP部分 1.下载源码 git clone https://github.com/ana52070/MCP_Control_STM32.git cd MCP_Control_STM32 cd mcp-led_oled2. 创建并激活虚拟环境 为了避免不同项目之间的依赖冲突&#xff0c;建议使用虚拟环境。根据你的操作系统和 Python 版本&#xff0c;…...

Linux-Ubuntu安装Stable Diffusion Forge

SD Forge在Win上配置起来相对简单且教程丰富&#xff0c;而在Linux平台的配置则稍有门槛且教程较少。本文提供一个基于Ubuntu24.04发行版&#xff08;对其他Linux以及SD分支亦有参考价值&#xff09;的Stable Diffusion ForgeUI安装配置教程&#xff0c;希望有所帮助 本教程以N…...

LoRA(Low-Rank Adaptation)原理详解

LoRA(Low-Rank Adaptation)原理详解 LoRA(低秩适应)是一种参数高效微调(Parameter-Efficient Fine-Tuning, PEFT)技术,旨在以极低的参数量实现大模型在特定任务上的高效适配。其核心思想基于低秩分解假设,即模型在适应新任务时,参数更新矩阵具有低秩特性,可用少量参…...

分享一个可以用GPT打标的傻瓜式SD图片打标工具——辣椒炒肉图片打标助手

一、打标效果展示 请参考下图&#xff0c;了解最终的打标效果&#xff1a; 打标速度提升百分之300&#xff1b; 打标成本&#xff1a; gpt4o每百张图约5毛rmb&#xff1b; gpt4o-mini价格更低&#xff1b; 更有claude&#xff0c;grok&#xff0c;gemini&#xff0c;豆包等…...

实战项目2(03)

目录 任务场景一【重点】 【sw1配置】 【sw2配置】 任务场景二【重点】 【sw1配置】 【sw2配置】 【sw3配置】 任务场景一【重点】 掌握基于SVI实现跨VLAN通信——某公司网络为了减少广播包对网络的影响&#xff0c;网络管理员对网络进行了VLAN划分&#xff0c;完成VLA…...

PyCharm软件下载和配置Python解释器

以下是详细的PyCharm下载及解释器环境配置步骤&#xff1a; 有什么问题可以留评论&#xff08;看见会回复的&#xff09; 一、PyCharm下载 1. 访问官网 进入JetBrains官网&#xff1a;https://www.jetbrains.com/pycharm/ 2. 选择版本 Community版&#xff08;免费&…...

《从零构建一个简易的IOC容器,理解Spring的核心思想》

大家好呀&#xff01;今天我们要一起探索Java开发中最神奇的魔法之一 —— Spring框架的IOC容器&#xff01;&#x1f9d9;‍♂️ 我会用最最最简单的方式&#xff0c;让你彻底明白这个看似高深的概念。准备好了吗&#xff1f;Let’s go! &#x1f680; 一、什么是IOC容器&…...

差分与位移算子

差分与位移算子是数值分析和离散数学中处理序列或离散函数的重要工具。它们通过算子代数简化差分的计算和分析&#xff0c;以下是关键概念和关系的总结&#xff1a; 1. 位移算子&#xff08;Shift Operator&#xff09; 定义&#xff1a; 位移算子 ( E ) 将函数 ( f(x) ) 沿自变…...

Robot之VideoMimic:《Visual Imitation Enables Contextual Humanoid Control》翻译与解读

Robot之VideoMimic&#xff1a;《Visual Imitation Enables Contextual Humanoid Control》翻译与解读 导读&#xff1a;这篇论文介绍了VIDEOMIMIC&#xff0c;一个基于视觉模仿的真实到模拟到真实流水线&#xff0c;用于训练人形机器人执行上下文相关的全身动作。该方法通过分…...

【Java学习日记34】:this关键字和成员变量

为什么不需要加 this&#xff1f; 作用域规则&#xff1a; Java编译器在查找变量时遵循“就近原则”。 先在当前方法内查找局部变量或参数。 若找不到&#xff0c;则去类的成员变量中查找。 getName() 的上下文&#xff1a; 该方法没有参数或局部变量名为 name&#xff0c;因…...

包名查看器APP:高效管理手机应用的实用工具

包名查看器APP是一款功能强大的文件查看软件&#xff0c;专为安卓用户设计&#xff0c;能够帮助用户快速了解手机上安装和未安装的APK包信息。作为酷安首发的APK信息查看工具&#xff0c;它提供了比系统设置更详细的信息&#xff0c;如版本号、包名、MD5等&#xff0c;帮助用户…...

左右括号的最小处理次数

1、题目描述 多多君在处理一个由左结号(和右语号&#xff09;组成的字符串&#xff0c;多多君每次处理时可以顺序读取一个字符或者一个有效括号子串&#xff0c;求问多多的最小处理次数。 输入描述&#xff1a; 第一行为一个整数N&#xff0c;表示字符串长度&#xff08;1<…...

22.第二阶段x64游戏实战-分析周围对象类型

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 上一个内容&#xff1a;21.第二阶段x64游戏实战-分析采集物偏移 上一个内容里发现采集物的名字通过我们…...

【C/C++】无符号调试:GDB解栈实战指南

文章目录 无符号调试&#xff1a;GDB解栈实战指南1 生成并加载 Core Dump2 查看原始堆栈信息&#xff08;地址形式&#xff09;3 确认加载的共享库地址范围4 手动转换地址为函数名5 反汇编关键代码段6 加载外部符号文件&#xff08;如有&#xff09;7 结合系统库文档分析8 示例…...

梦熊联盟:202505基础语法-题解

202505基础语法-题解 T1 - 九的倍数 解法&#xff1a; 对于 9 的倍数&#xff0c;只需要判定其各位的数码和是否为 9 的倍数即可。 例如判断一个数是不是 9 的倍数&#xff0c;只要判断其各位数字之和是不是 9 的倍数&#xff0c;因为一个数能被 9 整除当且仅当它的各位数字之和…...

Java SE(11)——内部类

1.内部类 定义&#xff1a;Java中的内部类(Inner Class)是指在一个类的内部定义的类。 使用场景&#xff1a;当一个类的内部&#xff0c;存在一个部分需要完成的结构进行描述&#xff0c;而该内部结构只为外部类提供服务&#xff0c;那么这个内部结构就可以使用内部类&#xff…...

优化审核模块响应时间从8s降至1.2s的数据库解决方案

优化审核模块响应时间从8s降至1.2s的数据库解决方案 要优化审核模块的数据库性能&#xff0c;需要从多个层面进行分析和优化。以下是具体的SQL语句设计和优化方案&#xff1a; 1. 分析当前性能瓶颈 首先需要找出慢查询&#xff1a; -- 查看慢查询日志中的审核模块相关查询 …...

YOLO-World:基于YOLOv8的开放词汇目标检测

文章目录 前言1、出发点2、方法2.1.TextEncoder2.2.ReparmVLPAN2.3.输出头 3、实验3.1.数据集3.2.LVIS测试集 总结 前言 本文介绍一篇来自腾讯的开放词汇检测工作&#xff0c;发表自CVPR2024&#xff0c;论文链接&#xff0c;开源地址。 1、出发点 GroundingDINO在开放词汇检测…...

NX989NY104美光科技芯片NY109NY113

NX989NY104美光科技芯片NY109NY113 存储市场新势力&#xff1a;美光科技的崛起与技术突围 在半导体行业波澜壮阔的浪潮中&#xff0c;美光科技宛如一颗璀璨的明珠&#xff0c;以其独特的技术实力和敏锐的市场洞察力&#xff0c;在存储领域占据了重要的一席之地。尤其是其旗下…...

LabVIEW的PID参数自适应控制

在工业控制领域&#xff0c;PID 控制凭借结构简单、稳定性好、工作可靠等优点被广泛应用。然而&#xff0c;传统固定参数的 PID 控制在面对复杂多变的工况时&#xff0c;控制效果往往难以达到最优。基于 LabVIEW 实现 PID 控制根据情况选择参数&#xff08;即参数自适应调整&am…...

Quartus与Modelsim-Altera使用手册

目录 文章内容&#xff1a; 视频内容&#xff1a; Quartus&#xff1a; ModelSim&#xff1a; 顶层设计与子模块&#xff1a; 只是对所查阅的相关文章的总结与视频总结 文章内容&#xff1a; 这篇对基础操作很详细&#xff1a; 一、Quartus II软件的使用_quartus2软件上…...

设计模式之工厂模式(二):实际案例

设计模式之工厂模式(一) 在阅读Qt网络部分源码时候&#xff0c;发现在某处运用了工厂模式&#xff0c;而且编程技巧也用的好&#xff0c;于是就想分享出来&#xff0c;供大家参考&#xff0c;理解的不对的地方请多多指点。 以下是我整理出来的类图&#xff1a; 关键说明&#x…...

数据可视化大屏——智慧社区内网比对平台

综述分析&#xff1a; 智慧社区内网数据比对信息系统 这段代码实现了一个智慧社区内网数据比对信息系统的前端界面&#xff0c;采用三栏式布局展示各类社区安全相关数据。界面主要由左侧数据统计、中间地图展示和右侧数据分析三部分组成&#xff0c;使用了多种图表可视化技术…...

Spark任务调度流程详解

1. 核心调度组件 DAGScheduler&#xff1a;负责将Job拆分为Stage&#xff0c;处理Stage间的依赖关系。 TaskScheduler&#xff1a;将Task分配到Executor&#xff0c;监控任务执行。 SchedulerBackend&#xff1a;与集群管理器&#xff08;如YARN、K8s&#xff09;通信&#x…...

LeetCode 215题解 | 数组中的第K个最大元素

数组中的第K个最大元素 一、题目链接二、题目三、算法原理四、编写代码 一、题目链接 数组中的第K个最大元素 二、题目 三、算法原理 法一&#xff1a;排序 法二&#xff1a;优先级队列&#xff08;堆&#xff09; 重点看法二&#xff1a; 默认建大堆&#xff0c;意味着以…...

探秘 Cursor 核心:解锁系统提示词的进阶之路

在 AI 编程领域&#xff0c;Cursor 无疑是一颗耀眼的明星&#xff0c;其母公司 Anysphere 在短短三个月内&#xff0c;估值从 25 亿美元狂飙至 100 亿美元&#xff0c;这样的发展速度令人咋舌。而 Cursor 强大功能背后的核心 —— 系统提示词&#xff0c;始终笼罩着一层神秘的面…...

ElasticSearch入门详解

1.ElasticSearch 1.1 ElasticSearch(简称es) Elasticsearch是用Java开发并且是当前最流行的开源的企业级搜索引擎。 能够达到实时搜索&#xff0c;稳定&#xff0c;可靠&#xff0c;快速&#xff0c;安装使用方便。 客户端支持Java、.NET&#xff08;C#&#xff09;、PHP、Py…...

【计算机网络01】 网络组成与三种交换方式

【参考资料】 《自顶向下的计算机网络第八版》湖科大计算机网络&#xff08;b站&#xff09;王道考研&#xff08;b站&#xff09; 文章目录 一、网络基础概念解析1.1 网络、互联网与因特网 二、因特网发展三阶段&#xff08;了解&#xff09;三、ISP3.1 ISP基本概念3.2 基于I…...

计算机网络——以太网交换机

目录 交换机的作用 以太网交换机的自学习功能 因为以太网交换机有自学习功能&#xff0c;所以以太网交换机支持即插即用 交换机的作用 它工作在数据链路层&#xff0c;为结点转发帧&#xff0c;并且可以根据一个帧的目的MAC地址去进行相应的转发&#xff0c;以及交换机的每…...

机器视觉开发教程——C#如何封装海康工业相机SDK调用OpenCV/YOLO/VisionPro/Halcon算法

目录 引言前期准备Step1 创建工程Step2 创建接口2.1定义操作相机实例接口方法2.2定义设置相机参数接口方法&#xff08;部分&#xff09; Step3 创建基类3.1定义操作相机实例&&设置相机参数的抽象层3.2定义操作相机实例&&设置相机参数的公用方法1.获取当前帧图…...

c++STL-string的模拟实现

cSTL-string的模拟实现 string的模拟实现string的模拟线性表的实现构造函数析构函数获取长度&#xff08;size&#xff09;和获取容量&#xff08;capacity&#xff09;访问 [] 和c_str迭代器&#xff08;iterator&#xff09;交换swap拷贝构造函数赋值重载&#xff08;&#x…...

HTTP 和 WebSocket 的区别

✅ 一、定义对比 协议简要定义HTTP一种基于请求-响应模式的、无状态的应用层协议&#xff0c;通常用于客户端与服务器之间的数据通信。WebSocket一种全双工通信协议&#xff0c;可以在客户端和服务器之间建立持久连接&#xff0c;实现实时、低延迟的数据传输。 ✅ 二、通信方式…...

【Tools】Visual Studio使用经验介绍(包括基本功能、远程调试、引入第三方库等等)

这里写目录标题 1. VS基本使用1.1. 快捷键1.2. 查看变量地址1.3. 查看代码汇编1.4. visual studio 热重载功能的使用1.5. vs远程服务器调试1.6. 引入第三方库VLD1.7. release debug模式 1. VS基本使用 1.1. 快捷键 ctrl c :复制光标所在行 注意&#xff1a;只需要光标在这…...

一周内学完计算机网络课程之二:计算机网络物理层的理解

消失人口回归&#xff0c;重新开始学习新知识。再次伟大。 物理层详解 需要理解的几个概念&#xff1a; 曼彻斯特编码、差分曼彻斯特编码 码元&#xff1a;构成信号的基本单元 调制&#xff1a; 通信中的调制是一种将原始信号&#xff08;如音频、视频、数据等&#xff09;转…...

Python OpenCV性能优化与部署实战指南

在计算机视觉领域&#xff0c;OpenCV作为开源视觉库的标杆&#xff0c;其性能表现直接影响着从工业检测到AI模型推理的各类应用场景。本文结合最新技术趋势与生产实践&#xff0c;系统性梳理Python环境下OpenCV的性能优化策略与部署方案。 一、性能优化核心技术矩阵 1.1 内存…...

深度解析:可视化如何重塑销售策略制定与执行

为什么你的销售策略总是“听起来挺对&#xff0c;做起来却没用”&#xff1f; 你有没有遇到过这样的情况&#xff1a; 销售团队天天跑客户&#xff0c;但业绩还是上不去&#xff1b;市场部说数据在增长&#xff0c;销售部却觉得“根本没转化”&#xff1b;高层开会时信心满满…...

opencv关键点检测

python 使用opencv进行图片关键点检测 功能&#xff1a; 在一张图片中裁剪出一块小图 使用cv2中 cv2.SIFT_create() SIFT检测器检测关键点 匹配原图和小图的关键点 import cv2 import numpy as np # 读取图像 img1 cv2.imread(rE:\234947.jpg, cv2.IMREAD_GRAYSCALE) img…...

C#游戏开发中的注意事项

目录 一、性能优化:提升游戏运行效率 1. 避免不必要的循环和迭代 2. 减少字符串拼接 3. 利用Unity的生命周期函数 4. 使用对象池(Object Pooling) 二、内存管理:避免内存泄漏和资源浪费 1. 及时释放非托管资源 2. 避免空引用异常 3. 合理使用引用类型和值类型 4. …...

MySQL的锁

锁 概述&#xff1a;锁是计算机协调多个线程或进程并发访问某一资源的机制。如何保证数据库中并发的一致性&#xff0c;有效性&#xff0c;这就是锁的作用。 分类&#xff1a; 全局锁 对数据库实例加锁&#xff0c;加锁之后&#xff0c;处于只读状态&#xff0c;后续的DML语句…...

学习黑客5 分钟小白弄懂Windows Desktop GUI

5 分钟小白弄懂Windows Desktop GUI &#x1f5a5;️ 大家好&#xff01;今天我们将深入浅出地探索Windows桌面图形用户界面(GUI)——这是我们每天与计算机交互的"门面"。无论你是刚开始接触计算机&#xff0c;还是想在TryHackMe等平台上提升安全技能&#xff0c;理…...

机器人运动控制原理浅析-UC Berkeley超视觉模态模型

加州伯克利发布的超视觉多感知模态融合(FuSe, Fuse Heterogeneous Sensory Data)模型&#xff0c;基于视觉、触觉、听觉、本体及语言等模态&#xff0c;利用自然语言跨模态对齐(Cross-Modal Grounding)优调视觉语言动作等通用模型&#xff0c;提高模型任务成功率。 总体框架 …...

【计算机网络】网络IP层

&#x1f4da; 博主的专栏 &#x1f427; Linux | &#x1f5a5;️ C | &#x1f4ca; 数据结构 | &#x1f4a1;C 算法 | &#x1f152; C 语言 | &#x1f310; 计算机网络 上篇文章&#xff1a;传输层协议TCP 下篇文章&#xff1a;数据链路层 文章摘要&#xff1…...

Nginx重写功能

目录 一 . 简介 二. if指令 2.1基本语法 2.2 举例说明 2.3 配置实例 三. return 3.1 基本语法 3.2 配置实例 四. set指令 4.1 基本语法 4.2 举例说明 4.3 配置实例 五.break指令 5.1 作用 5.2 举例说明 5.3 配置实例 六.rewrite指令 6.1 基本语法 6.2 配…...

2025-05-11 项目绩效域记忆逻辑管理

好的&#xff0c;我们可以用一个故事来帮助记忆这些规划绩效域的要素&#xff0c;同时通过逻辑关系来串联它们。以下是一个故事化的版本&#xff1a; 《项目管理的奇幻之旅》 在一个遥远的王国里&#xff0c;有一个勇敢的项目经理名叫小K。小K被国王赋予了一个艰巨的任务&…...