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

news2024/11/26 10:45:20

第一章:并发编程导论

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.coloradmin.cn/o/1632227.html

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

相关文章

基于 dockerfile 编写LNMP

目录 一. 环境准备 二. 部署 nginx 2.1 建立工作目录,并上传需要的安装包 2.2 配置 nginx.conf 文件 2.3 编写 dockerfile 2.4 构建一个新的镜像 2.5 启动一个新的容器 三. 部署MySQL 3.1 建立工作目录,并上传安装包 3.2 编写 Dockerfile 3.…

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

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

源码编译安装curl _ 统信UOS _ 麒麟KOS _ 中科方德

原文链接:源码编译安装curl | 统信UOS | 麒麟KOS | 中科方德 Hello,大家好啊!今天我们来探讨一个非常实用的话题:在统信UOS、麒麟KOS以及中科方德桌面操作系统上如何从源码编译安装curl。Curl是一个广泛使用的命令行工具和库&…

【Kafka】Kafka高性能之道(六)

Kafka高性能之道 Kafka高性能原因 高效使用磁盘 1)顺序写磁盘,顺序写磁盘性能高于随机写内存。 2)Append Only 数据不更新,无记录级的数据删除(只会整个segment删s除)。读操作可直接在page cache内进行。如果进程重启,JVM内的cache会失效&a…

Pandas dataframe 中显示包含NaN值的单元格

大部分教程只讲如何打印含有NA的列或行。这个函数可以直接定位到单元格,当dataframe的行和列都很多的时候更加直观。 # Finding NaN locations for df.loc def locate_na(df):nan_indices set()nan_columns set()for col, vals in df_descriptors.items():for in…

grafana监控模板 regex截取ip地址

查看prometheus的node服务启动指标up,也可以查看其他的服务 配置监控模板 配置正则截取ip regex截取ip地址 /.*instance"([^"]*):9100*/ #提取(instance")开头,(:9001)结束字段

Qt Creator中变量与函数的注释 - 鼠标悬浮可显示

Qt Creator中变量与函数的注释 - 鼠标悬浮可显示 引言一、变量注释二、函数注释三、参考链接 引言 代码注释在软件开发中起着至关重要的作用。它们不仅有助于开发者理解和维护代码,还能促进团队协作,提高代码的可读性和可维护性。适当的注释应该是简洁明…

头脑风暴式会议设计6步法

头脑风暴是一种常用的会议讨论工具,可以释放参与者的思想,让参与者更加有创意地思考,产生新的想法和见解。引导者在设计会议时,遵循一定的步骤和流程,便能高效激发创新思维,共创出有效的问题解决方案。下图…

百度竞价开户详解:步骤、优势与注意事项

随着互联网的普及,网络营销已成为企业不可或缺的一部分。其中,百度竞价作为一种高效的网络推广方式,受到了越来越多企业的青睐。本文将详细介绍百度竞价开户的流程、优势以及注意事项,帮助企业更好地利用这一工具提升品牌知名度和…

linux运行python怎么结束

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

正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-6.5

前言: 本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM(MX6U)裸机篇”视频的学习笔记,在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。…

stm32单片机开发四、USART

串口的空闲状态时高电平,起始位是低电平,来打破空闲状态的高电平 必须要有停止位,停止位一般为一位高电平 串口常说的数据为8N1,其实就是8个数据位(固定的),N就是none,也就是0个校验…

用socat验证multicase(组播)和broadcast(广播) with k8s容器环境

安装socat 网络允许的话,可以使用yum install -y socat进行安装。 如果是在容器里面运行,建议使用静态链接的socat: 可以从此处下载: Release socat-v1.7.4.4 ernw/static-toolbox GitHub 确定网络接口地址和组播地址 #kubectl exec -i…

低GPU利用率的实证研究;可解决数学问题的数据合成新范式;大规模合成数学推理的指令微调数据;大模型改进推荐系统

编者按:欢迎阅读“科研上新”栏目!“科研上新”汇聚了微软亚洲研究院最新的创新成果与科研动态。在这里,你可以快速浏览研究院的亮点资讯,保持对前沿领域的敏锐嗅觉,同时也能找到先进实用的开源工具。 本期内容速览 …

KT-0911兔气管插管

简单介绍: 在医学和生物学常用兔进行实验,实验中经常需要给兔气管插管以进行机械通气或气管给药等操作。 详情介绍: 技术参数: 1.材质:PVC注塑一体成型 2.插管外径尺寸:5mm 3.适用动物:兔…

10分钟了解数据质量管理-奥斯汀格里芬 Apache Griffin

在不重视数据质量的大数据发展时期,Griffin并不能引起重视,但是随着数据治理在很多企业的全面开展与落地,数据质量的问题开始引起重视。 1.Griffin简介 Griffin是一个开源的大数据数据质量解决方案,由eBay开源,它支持…

FPlan Part1 EP1(MySQL)

今天完成了MySQL的第一部分,计划分为三部分,预计将在五一假期前完成,以及一个Java小游戏。 重点如下

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

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

AI图书推荐:AI驱动的图书写作工作流—从想法构思到变现

《AI驱动的图书写作工作流—从想法到变现》(AI-Driven Book Creation: From Concept to Cash)是Martynas Zaloga倾力打造的一本实用指南,它巧妙地将写作艺术与人工智能前沿技术相结合。此书不仅揭示了AI在图书出版领域的无限潜力,…

网盘—上传文件

本文主要讲解网盘里面关于文件操作部分的上传文件,具体步骤如下 目录 1、实施步骤: 2、代码实现 2.1、添加上传文件协议 2.2、添加上传文件槽函数 2.3、添加槽函数定义 2.4、关联上传槽函数 2.5、服务器端 2.6、在服务器端添加上传文件请求的ca…