Python并发编程:揭开多线程与异步编程的神秘面纱

第一章:并发编程导论

1.1 并发与并行概念解析

1.1.1 并发性与并行性的区别

想象一下繁忙的厨房中多位厨师同时准备不同的菜肴——即使他们共享有限的空间和资源,也能协同工作,这就是并发性的一个生动比喻。并发性意味着多个任务在同一时间段内看似同时进行,但实际上可能交替执行。而在并行性中,多个任务真正意义上是在同一时刻由不同处理器或核心独立完成。例如,多台烤箱同时烹饪不同的菜品,每台烤箱都是一个独立的处理器,各自执行各自的烹饪任务。

1.1.2 并发编程的重要性及其挑战

在现代软件工程中,并发编程至关重要,因为它能够充分利用多核处理器的优势,有效提高系统吞吐量和响应速度。然而,它也带来了诸如竞态条件、死锁、活锁和资源争抢等问题。如同一场精心编排的芭蕾舞剧,若不妥善安排舞者们(即线程)的移动和动作(即状态变更),就可能导致舞台上的混乱甚至演出中断。

1.2 Python中的并发模型

1.2.1 全局解释器锁(GIL)的影响

全局解释器锁(Global Interpreter Lock, GIL)是Python并发编程绕不开的话题。如同独木桥上的守卫,GIL确保任何时候只有一个线程在执行Python字节码。尽管保证了内存安全,但也意味着在单个进程中,即便有多核CPU,也无法实现真正的并行计算。这对于CPU密集型任务来说,可能会导致性能瓶颈。

1.2.2 Python对多线程、多进程的支持

尽管受到GIL约束,Python依然提供了丰富的并发原语。对于多线程编程,可通过内置的threading模块创建和管理线程;而对于突破GIL限制,多进程编程则是一个可行的选择,multiprocessing模块为此提供了强大的支持。接下来我们将深入探索这两个领域,结合实例代码展示如何创建线程、解决并发问题以及在适当场合下使用多进程。例如,下面是一个简单的多线程实例:

import threading

def worker(num):
    """线程执行的任务"""
    print(f"Worker {num} is running.")

# 创建并启动两个线程
threads = [threading.Thread(target=worker, args=(i,)) for i in range(2)]
for t in threads:
    t.start()
for t in threads:
    t.join()  # 确保所有线程执行完毕

这段代码展示了如何在Python中创建并启动两个线程来并发执行同一个函数。随着章节推进,我们将进一步讨论线程间的同步机制以及在不同场景下选择合适的并发策略。

第二章:Python多线程魔法阵

2.1 线程基础与线程生命周期

2.1.1 threading模块介绍

在Python的世界里,多线程犹如魔法师手中的魔杖,通过threading模块我们可以轻松地编织出并发执行的神奇景象。这个模块提供了创建、管理线程的基本结构,允许我们定义线程任务,进而实现任务的并发执行。线程就像一个个独立的工人,在同一个进程的工厂里各司其职,共同推进整体工作的进度。

2.1.2 创建与启动线程实例

想象一下,你正在经营一家咖啡厅,每位服务员就是一个线程,负责不同的订单任务。创建线程的过程就如同雇佣一位新服务员,为其分配特定的工作任务:

import threading

class CoffeeOrderThread(threading.Thread):
    def __init__(self, order_id):
        super().__init__()
        self.order_id = order_id

    def run(self):
        print(f"开始制作订单{self.order_id}的咖啡...")
        # 在此处模拟咖啡制作过程(比如耗时操作)
        time.sleep(2)
        print(f"订单{self.order_id}的咖啡已完成!")

# 创建两个线程实例
order1 = CoffeeOrderThread(1)
order2 = CoffeeOrderThread(2)

# 启动线程
order1.start()
order2.start()

# 确保所有线程都完成工作
order1.join()
order2.join()
2.1.3 线程同步机制:锁、条件变量、信号量等

为了防止咖啡厅里的原料被同时取用造成混乱,我们需要引入同步机制。就好比给咖啡豆罐子加一把锁,只有拿到钥匙的服务员才能取用豆子:

import threading

coffee_lock = threading.Lock()

def prepare_coffee(order_id):
    with coffee_lock:
        print(f"开始为订单{order_id}磨咖啡豆...")
        # 磨豆子(同步操作)
        time.sleep(1)
        print(f"完成订单{order_id}的磨豆工作!")

# 分别在两个线程中执行
threads = [threading.Thread(target=prepare_coffee, args=(i,)) for i in range(1, 3)]
for thread in threads:
    thread.start()
for thread in threads:
    thread.join()
2.1.4 经典多线程问题及解决方案
  • 死锁与饥饿问题
    死锁就像是咖啡厅里的服务员们都互相等待对方释放所需的资源而停滞不前。解决死锁的关键在于避免循环等待和资源抢占,可以通过设置超时、资源有序申请等方式预防。

示例:

lock1 = threading.Lock()
lock2 = threading.Lock()

def deadlock_thread(id):
	if id == 1:
		lock1.acquire()
		print("线程1获得第一个锁")
		try:
			lock2.acquire(True, 2)  # 设置超时避免无限等待
		except threading.LockTimeout:
			print("线程1获取第二个锁超时,避免了死锁")
		else:
			print("线程1获得了两个锁,正常执行")
	elif id == 2:
		lock2.acquire()
		print("线程2获得第一个锁")
		try:
			lock1.acquire(True, 2)
		except threading.LockTimeout:
			print("线程2获取第二个锁超时,避免了死锁")
		else:
			print("线程2获得了两个锁,正常执行")

# 创建并启动线程
thread1 = threading.Thread(target=deadlock_thread, args=(1,))
thread2 = threading.Thread(target=deadlock_thread, args=(2,))
thread1.start()
thread2.start()
  • 生产者消费者问题示例
    生产者消费者问题是多线程同步的经典案例,就像吧台服务员和烘焙师之间的协作。生产者(烘焙师)不断制作面包,消费者(服务员)则在面包做好时将其取出上桌。借助队列和条件变量可以完美解决这个问题。
import queue
import threading

bread_queue = queue.Queue(maxsize=5)
stop_event = threading.Event()

def producer():
	while not stop_event.is_set():
		bread = make_bread()  # 制作面包
		bread_queue.put(bread)
		print("生产者制作了一块面包")

def consumer():
	while not stop_event.is_set() or not bread_queue.empty():
		if not bread_queue.empty():
			bread = bread_queue.get()
			serve_customer(bread)  # 上桌面包
			print("消费者为顾客送上一块面包")

def start_threads():
	producer_thread = threading.Thread(target=producer)
	consumer_thread = threading.Thread(target=consumer)
	producer_thread.start()
	consumer_thread.start()

	# 运行一段时间后停止
	time.sleep(5)
	stop_event.set()

	# 等待所有线程结束
	producer_thread.join()
	consumer_thread.join()

start_threads()

2.2 Python多线程实践策略

2.2.1 I/O密集型任务中的多线程优化

在I/O密集型任务如网络请求或文件读写中,由于大量时间花费在等待外部响应而非CPU运算,多线程能够显著提高效率。即使受制于GIL,每个线程仍能在等待I/O操作时释放GIL,让其他线程有机会执行。

2.2.2 CPU密集型任务中的多线程局限性

对于纯CPU计算任务,由于GIL的存在,多线程在单个进程中并不能带来实质性的并行计算优势。这时,多进程或多进程与异步I/O的组合将是更好的选择。

2.2.3 使用concurrent.futures模块简化多线程编程

Python标准库中的concurrent.futures模块提供了高层级的异步接口,使得多线程编程变得更加简洁易用。通过ThreadPoolExecutor,我们可以方便地管理和调度一组线程,从而简化并发任务的组织和执行。

from concurrent.futures import ThreadPoolExecutor

with ThreadPoolExecutor(max_workers=5) as executor:
    future_to_url = {executor.submit(fetch_data, url): url for url in urls}
    
    for future in concurrent.futures.as_completed(future_to_url):
        url = future_to_url[future]
        try:
            data = future.result()
        except Exception as exc:
            print(f"获取 {url} 数据时发生错误: {exc}")
        else:
            process_data(data)

第三章:异步编程的奇妙世界

3.1 异步编程理念与事件驱动模型

3.1.1 单线程异步I/O概述

想象一个热闹的餐厅,一位服务员在单一的工作台上接待众多客人。虽然只有一人服务,但服务员并不会因为等待某个客人的菜单确认而闲下来,而是会在等待的同时去询问其他客人的需求,然后高效地来回穿梭于厨房与餐桌之间。这种高效的运作模式就是异步编程的一种直观体现。在计算机术语中,单线程异步I/O意味着即使在一个单独的线程中,也可以通过非阻塞式I/O操作和事件循环机制,使程序在等待I/O完成时继续处理其他任务,大大提高了系统的并发能力。

3.1.2 Python中的异步框架比较(asyncio, Twisted等)

在Python生态系统中,有两个突出的异步编程框架:asyncio 和 Twisted。asyncio 是 Python 3.4 版本起引入的标准库,以其简洁易用的 async/await 关键字和 EventLoop 构建的异步编程模型,迅速成为现代Python异步编程的主流工具。而Twisted作为历史悠久的异步框架,尤其擅长网络编程,提供了广泛的协议支持,尽管学习曲线稍陡峭,但在一些复杂的网络应用中仍然有着不可替代的地位。

3.2 Python asyncio模块详解

3.2.1 async/await关键字与协程基础

在asyncio的世界里,async关键字用于定义一个协程函数,它们像普通的函数一样可以包含任意Python语句,但是当遇到await表达式时会暂停执行,直到其后的异步操作完成。协程就好似接力赛中的运动员,当一个任务到达需要等待的环节时,它会把控制权交给下一个等待执行的协程。

import asyncio

async def fetch_data(url):
    response = await get_http_response(url)  # 假设get_http_response是异步HTTP请求函数
    return response.text()

async def process_urls(urls):
    tasks = [fetch_data(url) for url in urls]
    results = await asyncio.gather(*tasks)
    for result in results:
        print(result)

# 启动事件循环
loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(process_urls(["http://example.com"]))
finally:
    loop.close()
3.2.2 Future、Task与EventLoop的核心组件
  • Future:代表未来某个时刻可能完成的结果,它是异步编程中的基本构造块,封装了异步操作的结果或者异常。

  • Task:是对Future的封装,增加了调度和取消功能,是EventLoop上运行的具体工作单元。

  • EventLoop:是整个异步编程的大脑,负责调度协程,监控Future的状态变化,以及处理定时器和其他异步资源。当Future完成时,EventLoop会触发适当的回调,从而推动协程的执行。

3.2.3 异步编程实战:HTTP请求、文件读写等案例
import aiohttp  # 异步HTTP客户端库

async def fetch_async(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()

async def main():
    html_content = await fetch_async('http://example.com')
    print(html_content)

# 使用asyncio.run在主线程直接运行异步任务
asyncio.run(main())

3.3 异步编程的优势与应用场景

3.3.1 高并发场景下的性能提升

在高并发场景,如Web服务器、实时聊天应用或大规模数据抓取等,异步编程能够最大化利用单线程资源,减少不必要的上下文切换开销,使得单个线程可以处理更多的连接或请求,从而显著提升系统性能。

3.3.2 异步在实时数据流处理与Web服务器开发中的应用

在实时数据流处理中,例如股票交易实时报价系统、物联网传感器数据接收等,异步编程可以帮助程序及时响应各种事件,保证数据的实时性和准确性。而在Web服务器开发中,采用异步框架如Sanic、FastAPI配合

第四章:多进程编程与混合模式并发

4.1 multiprocessing模块介绍

4.1.1 进程间通信(IPC)机制

在Python中,multiprocessing模块是实现多进程编程的重要基石。相比于多线程,进程间不存在全局解释器锁(GIL)的问题,因此在CPU密集型任务上,多进程能充分利用多核CPU的优势。进程间通信(IPC, Inter-Process Communication)是多进程编程中的关键环节,通过管道(Pipe)、队列(Queue)、共享内存(Shared Memory)、信号量(Semaphore)等机制,进程间可以交换数据和同步执行状态。

例如,我们可以通过multiprocessing.Queue来在进程间传递消息:

from multiprocessing import Process, Queue

def worker(q):
    while True:
        item = q.get()  # 获取队列中的任务
        if item is None:
            break  # 若收到None,则退出循环
        process_item(item)
        q.task_done()  # 表示一项任务已完成

def main():
    task_queue = Queue()
    
    # 创建多个工作者进程
    for _ in range(4):
        p = Process(target=worker, args=(task_queue,))
        p.start()

    # 将任务放入队列
    for task in tasks:
        task_queue.put(task)

    # 放入None来通知所有工作者进程结束
    for _ in range(4):
        task_queue.put(None)

    # 等待所有任务完成
    task_queue.join()

    # 关闭进程
    for p in processes:
        p.join()

if __name__ == "__main__":
    main()
4.1.2 Pool类与进程池的使用

multiprocessing.Pool类为多进程编程提供了一个更便捷的方式,它可以创建一个进程池来管理一组工作进程。当你有大量任务需要执行时,进程池可以有效地分配和回收进程资源,提高执行效率。以下是一个使用进程池的例子:

from multiprocessing import Pool

def process_number(number):
    # 模拟耗时操作
    return number * number

if __name__ == "__main__":
    numbers = [1, 2, 3, 4, 5]

    with Pool(processes=3) as pool:
        # 使用map函数将任务分发到进程池
        squared_numbers = pool.map(process_number, numbers)

    print(squared_numbers)

4.2 多进程与多线程对比分析

4.2.1 GIL限制下为何选择多进程

全局解释器锁(GIL)是Python解释器为了数据安全而在多线程环境下引入的一个机制,但它限制了线程在多核CPU上的并行执行。因此,对于那些需要充分利用多核CPU性能的CPU密集型任务,尤其是不受GIL影响的计算密集型场景,多进程成为了理想的解决方案。多进程不仅规避了GIL的制约,还因进程间内存隔离的特点减少了潜在的数据竞争风险。

4.2.2 根据任务类型选择合适的并发模型

选择多进程还是多线程,通常取决于具体的应用场景和任务特点。对于I/O密集型任务,由于大部分时间都在等待外部I/O操作完成,多线程可以很好地利用这些空闲时间片,即便受限于GIL,也能在一定程度上提高系统响应速度。而对于CPU密集型任务,多进程能够更好地发挥多核CPU的优势,避免因GIL造成的性能瓶颈。

综合考虑资源消耗、通信开销和任务特性等因素,灵活运用多进程、多线程,甚至是结合异步编程,可以构建出既能满足性能需求又能保持代码简洁的高效并发解决方案。

第五章:异步I/O与协程的最佳实践

5.1 基于asyncio的高级特性与设计模式

5.1.1 异步上下文管理器与异步生成器

在Python的asyncio库中,异步上下文管理器(Async Context Manager)是协程编写过程中不可或缺的一部分,它帮助我们在进入和离开上下文时执行异步操作。例如,当我们需要异步打开和关闭文件时,可以利用async with语法优雅地管理资源:

import asyncio
import aiofiles

async def read_file(file_path):
    async with aiofiles.open(file_path, mode='r') as file:
        content = await file.read()
    return content

async def main():
    content = await read_file('data.txt')
    print(content)

# 运行主协程
asyncio.run(main())

此外,异步生成器(Asynchronous Generator)也是asyncio中的一大亮点。它允许我们在协程中使用yield关键字,这样就能逐段生成或消费数据,非常适合处理大数据流或连续的异步操作:

async def async_generator_example():
    for i in range(10):
        await asyncio.sleep(1)  # 模拟异步延迟操作
        yield i

async def consume_generator(gen):
    async for value in gen:
        print(f"Received value: {value}")

async def main():
    generator = async_generator_example()
    await consume_generator(generator)

asyncio.run(main())
5.1.2 使用协程进行复杂流程控制

在复杂的异步场景中,协程可以嵌套使用,结合asyncio.create_taskasyncio.waitasyncio.gather等函数,形成层次丰富、逻辑清晰的异步流程。例如,我们可以用协程同时发起多个HTTP请求,并等待所有请求完成:

import asyncio
import aiohttp

async def fetch_page(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()

async def fetch_multiple_pages(urls):
    tasks = [asyncio.create_task(fetch_page(url)) for url in urls]
    responses = await asyncio.gather(*tasks)
    return responses

async def main():
    urls = ['https://example1.com', 'https://example2.com', 'https://example3.com']
    page_contents = await fetch_multiple_pages(urls)
    for idx, content in enumerate(page_contents):
        print(f"Response from {urls[idx]}: {content[:100]}...")

asyncio.run(main())

5.2 实战项目:构建高性能的并发服务

5.2.1 异步爬虫案例分析

设想一个异步爬虫项目,利用asyncio和aiohttp,我们可以并发地抓取多个网页的内容:

import asyncio
import aiohttp
from bs4 import BeautifulSoup

async def fetch_and_parse(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            text = await response.text()
            soup = BeautifulSoup(text, 'html.parser')
            title = soup.find('title').text
            return title

async def crawl_websites(urls):
    titles = []
    async with aiohttp.ClientSession() as session:
        tasks = [asyncio.create_task(fetch_and_parse(url)) for url in urls]
        for response in await asyncio.gather(*tasks):
            titles.append(response)
    return titles

async def main():
    urls = [
        'https://www.example1.com',
        'https://www.example2.com',
        'https://www.example3.com',
    ]
    titles = await crawl_websites(urls)
    for title in titles:
        print(title)

asyncio.run(main())
5.2.2 使用异步编程优化数据库操作

在数据库操作中,特别是涉及大量IO操作时,异步编程同样能大幅提升性能。例如,使用aiomysql或asyncpg库,我们可以异步地执行多个数据库查询:

import asyncio
import aiomysql

async def fetch_records(query, params):
    conn = await aiomysql.connect(host='localhost', user='user', password='pass', db='test_db')
    async with conn.cursor() as cur:
        await cur.execute(query, params)
        records = await cur.fetchall()
    conn.close()
    return records

async def main():
    queries = [("SELECT * FROM table1 WHERE condition1", params1),
               ("SELECT * FROM table2 WHERE condition2", params2)]
    tasks = [asyncio.create_task(fetch_records(query, params)) for query, params in queries]
    all_records = await asyncio.gather(*tasks)
    # 对结果进行合并或处理...

asyncio.run(main())

通过上述例子,我们可以看到异步编程在处理I/O密集型任务时展现出的强大威力,它能让我们的并发服务更加高效、响应更快,充分挖掘硬件潜力,从而满足实际业务中对于高并发和实时性处理的需求。

第六章:并发编程的未来展望与实践指南

6.1 并发编程的未来趋势与技术发展

随着计算技术的进步和多核处理器的普及,我们正迎来一个并发编程的黄金时代。未来的并发编程将更加注重简化开发者的工作流程,提供更高层次的抽象和工具,同时保证程序的性能和安全性。例如,随着异步编程语言特性的不断完善,如Python中的async/await语法,开发者将能够以更直观和简洁的方式编写并发代码。此外,云计算和容器化技术的发展也将推动并发编程模式的创新,如通过微服务架构和Kubernetes等容器编排工具,实现更灵活的资源管理和服务部署。

6.2 实践指南:构建高效并发应用的策略

在构建高效的并发应用时,开发者需要综合考虑任务的性质、系统资源和预期的性能目标。对于I/O密集型任务,多线程和异步编程是提升效率的有效手段;而对于CPU密集型任务,多进程和分布式计算可能是更好的选择。此外,合理利用缓存和消息队列等中间件,可以减轻数据库压力,提高数据处理速度。开发者还应关注并发编程中的错误处理和异常管理,确保应用的稳定性和可靠性。

6.3 持续学习与实践:提升并发编程技能的途径

并发编程是一个不断发展的领域,要求开发者持续学习最新的技术和最佳实践。参与开源项目、阅读技术博客和论坛、参加技术会议和研讨会,都是获取新知识和交流经验的好途径。同时,通过实际项目中的问题解决和性能优化,可以不断提升自己的并发编程技能。

在这里插入图片描述


关注gzh不灵兔,Python学习不迷路,关注后后台私信,可进wx交流群,进群暗号【人生苦短】~~~

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

getchar和putchar的用法

getchar() 和 putchar() 是一对字符输入/输出函数.他们通常比scanf() 和printf() 函数更快更便捷。 getchar()不带任何参数,其实getchar() 和putchar()与scanf() 和printf()功能相似。 接下来博主简单的跟大家解释一下。 1.getchar 通常把输入的字符赋予一个字符变…

uReport2 报表设计

最近刚好用到这个报表工具,刚开始接触都还不会用,学习了一下,在这边做个记录。 数据源 目前报表框架支持和使用的数据源连接有两种方式:添加数据库连接 和添加内置数据源连接。 进入报表设计 http://IP:端口/context-path/urepor…

计算机网络之传输层TCP\UDP协议

UDP协议 用户数据报协议UDP概述 UDP只在IP数据报服务之上增加了很少功能,即复用分用和差错检测功能 UDP的主要特点: UDP是无连接的,减少开销和发送数据之前的时延 UDP使用最大努力交付,即不保证可靠交付,可靠性由U…

一款神奇的地理数据可视化python库

在地理信息系统(GIS)和地理数据可视化领域,Python的易用性和强大的库支持使其成为处理地理数据的理想选择之一。今天我们介绍Cartopy库,它为地理数据可视化提供了强大的支持。无论是对于GIS专业人士还是对地理数据可视化感兴趣的初…

网络编程——TCP

socket socket类型 流式套接字(SOCK_STREAM) TCP 提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复、无丢失、无失序的发送且按发送顺序接收。内设置流量控制,避免数据流淹没慢的接收方。数据被看作是字节流,无长度限制。 数据报…

异常处理方式

在定义方法时,首先需要先对参数数据进行合法判断 数据若不合法,使用抛出异常的方式来告诉调用者,传递合法的数据进来 在方法内使用 throw 抛出指定异常对象,throw new XxxException(“异常产生原因”) 创建的是运行时异常&…

ROS学习笔记(14)拉普拉斯变换和PID

0.前提 近些时间在对睿抗的ROS仿真赛进行小组安排,对小组成员进行了一些安排,也要求他们以本次比赛写下自己的比赛经历博客,他们的培训由我来安排和负责,因此我得加吧油,起码保证我的进度得快过他们,才能安…

使用yolov8+QT+onnrunxtime进行开发的注意事项

1、本来想尝试做一个C的yolov8在QT5.15.2的应用; 因此,在实现这个目标的时候,我先用了yolov8自带的export进行导出,使用的代码很简单,如下所示: import os from ultralytics import YOLO# model YOLO(&q…

SpringBoot 快速开始 Dubbo RPC

文章目录 SpringBoot 快速开始 Dubbo RPC下载 Nacos项目启动项目的创建创建主项目接口定义服务的创建Dubbo 服务提供者的创建服务的消费者创建 添加依赖给 Provider、Consumer 添加依赖 开始写代码定义接口在 Provider 中实现在 Consumer 里面使用创建启动类 注册中心配置启动 …

绘唐科技AIGC怎么激活

绘唐科技AIGC怎么激活绘唐科技AIGC怎么激活绘唐科技AIGC怎么激活绘唐科技AIGC怎么激活 这里激活免费3天体验 Docshttps://qvfbz6lhqnd.feishu.cn/wiki/D3YLwmIzmivZ7BkDij6coVcbn7W

架构师技能:技术深度硬实力透过问题看本质--深入分析nginx偶尔502错误根因

以架构师的能力标准去分析每个问题,过后由表及里分析问题的本质,复盘总结经验,并把总结内容记录下来。当你解决各种各样的问题,也就积累了丰富的解决问题的经验,解决问题的能力也将自然得到极大的提升。励志做架构师的…

Spring IOC(二)

1. Bean的定义与获取 1.1 定义Bean 在Spring 中定义Bean的方式主要有三种&#xff1a; 1、基于XML配置文件的方式&#xff08;了解&#xff09;&#xff1a;通常会在配置文件中使用<bean>标签来定义Bean&#xff0c;并设置Bean的属性、依赖关系等信息。 2、基于注解的方…

C语言程序设计(一)

1、指令、程序、软件 2、计算机语言&#xff1a;机器语言、汇编语言、高级语言 高级语言的发展&#xff1a;非结构化语言&#xff08;FORTRAN&#xff09;、结构化语言&#xff08;C语言&#xff09;、面向对象的语言&#xff08;C、面向对象&#xff09; 3、源程序、二进制…

数据可视化在不同行业中有哪些应用?

数据可视化即通过图表的形式将数据的内在信息有逻辑性地呈现给用户&#xff0c;使用户更容易发现数据中蕴藏的规律&#xff0c;找出问题&#xff0c;进而做出决策&#xff1b;另一方面&#xff0c;数据可视化项目也是一张重要的名片&#xff0c;是企业数字化建设效果的呈现。本…

FPGA实现图像处理之【直方图均衡-寄存器版】

FPGA实现直方图统计 一、图像直方图统计原理 直方图的全称为灰度直方图&#xff0c;是对图像每一灰度间隔内像素个数的统计。即对一张图片中每隔二灰度值的像素数量做统计&#xff0c;然后以直方图的形式展现出来。图下的亮暗分布在直方图中就可以一目了然&#xff0c;直方图…

【数据结构与算法】力扣 225. 用队列实现栈

题目描述 请你仅使用两个队列实现一个后入先出&#xff08;LIFO&#xff09;的栈&#xff0c;并支持普通栈的全部四种操作&#xff08;push、top、pop 和 empty&#xff09;。 实现 MyStack 类&#xff1a; void push(int x) 将元素 x 压入栈顶。int pop() 移除并返回栈顶元…

AI项目二十:基于YOLOv8实例分割的DeepSORT多目标跟踪

若该文为原创文章&#xff0c;转载请注明原文出处。 前面提及目标跟踪使用的方法有很多&#xff0c;更多的是Deepsort方法。 本篇博客记录YOLOv8的实例分割deepsort视觉跟踪算法。结合YOLOv8的目标检测分割和deepsort的特征跟踪&#xff0c;该算法在复杂环境下确保了目标的准…

R语言的基本图形

一&#xff0c;条形图 安装包 install.packages("vcd") 绘制简单的条形图 barplot(c(1,2,4,5,6,3)) 水平条形图 barplot(c(1,2,4,5,6,3),horiz TRUE) 堆砌条形图 > d1<-c("Placebo","Treated") > d2<-c("None",&qu…

linux运行python怎么结束

假如你已经进入到【>>>】&#xff0c;那么输入【quit&#xff08;&#xff09;】&#xff0c;然后按一下回车键即可退出了。 如果是想要关闭窗口的&#xff0c;那么直接在这个窗口上按【ctrld】。

vue2集成ElementUI编写登录页面

目录 1. 整理目录文件&#xff1a; a. app.vue文件如下&#xff1a; b. Login.vue文件如下&#xff1a; c. router/index.js文件如下&#xff1a; d. 删除components中的文件&#xff1a; e. 最终项目目录整理如下&#xff1a; 2. 集成ElementUI编写登录页面 a. 安装El…
最新文章