Python 中的同步和异步编程:关键概念和应用

WBOY
发布: 2024-08-31 06:03:37
原创
626 人浏览过

Synchronous and Asynchronous Programming in Python: Key Concepts and Applications

同步编程
在同步编程中,任务是一个接一个地执行的。每项任务必须在下一项任务开始之前完成。这种线性方法很简单,但效率可能较低,尤其是在处理文件读取、网络请求或数据库查询等 I/O 密集型操作时。

import time

def task1():
    print("Starting task 1...")
    time.sleep(2)
    print("Task 1 completed")

def task2():
    print("Starting task 2...")
    time.sleep(2)
    print("Task 2 completed")

def main():
    task1()
    task2()

if __name__ == "__main__":
    main()
登录后复制

在此示例中,任务 1 必须在任务 2 开始之前完成。总执行时间是每个任务所花费时间的总和。

异步编程
异步编程允许多个任务同时运行,从而提高效率,特别是对于 I/O 密集型任务。 Python 的 asyncio 库提供了异步编程所需的工具。

import asyncio

async def task1():
    print("Starting task 1...")
    await asyncio.sleep(2)
    print("Task 1 completed")

async def task2():
    print("Starting task 2...")
    await asyncio.sleep(2)
    print("Task 2 completed")

async def main():
    await asyncio.gather(task1(), task2())

if __name__ == "__main__":
    asyncio.run(main())
登录后复制

在这个例子中,task1和task2并发运行,将总执行时间减少到最长任务所花费的时间。

潜在应用

Web 服务器和 API:

  • 同步:像 Flask 这样的传统 Web 框架按顺序处理请求。在处理大量请求时,这可能会成为瓶颈。
  • 异步:FastAPI 和 aiohttp 等框架使用异步编程来同时处理多个请求,从而提高吞吐量和性能。

实时消息传递应用程序:

  • 同步:如果按顺序处理每条消息,处理实时消息可能会导致延迟。
  • 异步:使用具有异步处理功能的 WebSocket(例如 websockets 库)可以实现实时双向通信,从而实现高性能聊天应用程序、实时通知等。

数据处理管道:

  • 同步:顺序处理大型数据集可能非常耗时。
  • 异步:异步任务可以同时获取、处理和存储数据,显着减少处理时间。像 aiohttp 和 aiomysql 这样的库可用于异步 HTTP 请求和数据库操作。

网页抓取:

  • 同步:顺序获取网页可能会很慢且效率低下。
  • 异步:使用aiohttp进行异步HTTP请求可以同时获取多个网页,加快网页抓取过程。

文件I/O操作:

  • 同步:顺序读取/写入大文件可能会阻塞其他操作。
  • 异步:使用 aiofile 的异步文件 I/O 操作可以通过允许其他任务同时运行来提高性能。

同步和异步之间的选择

  • 对 CPU 密集型任务使用同步编程,这些任务是计算密集型的,并且可以从顺序运行中受益。
  • 对 I/O 密集型任务使用异步编程,其中操作涉及等待外部资源,例如网络请求、文件 I/O 或数据库查询。

实时消息应用示例
让我们创建一个基本的实时消息应用程序,使用 FastAPI 作为后端,使用 WebSockets 进行实时通信。我们将使用 Streamlit 作为前端来显示消息。

后端(FastAPI + WebSockets)

1.安装依赖项:
pip install fastapi uvicorn websockets

2.后端代码(backend.py):

from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.responses import HTMLResponse
from typing import List

app = FastAPI()

class ConnectionManager:
    def __init__(self):
        self.active_connections: List[WebSocket] = []

    async def connect(self, websocket: WebSocket):
        await websocket.accept()
        self.active_connections.append(websocket)

    def disconnect(self, websocket: WebSocket):
        self.active_connections.remove(websocket)

    async def send_message(self, message: str):
        for connection in self.active_connections:
            await connection.send_text(message)

manager = ConnectionManager()

@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await manager.connect(websocket)
    try:
        while True:
            data = await websocket.receive_text()
            await manager.send_message(data)
    except WebSocketDisconnect:
        manager.disconnect(websocket)

@app.get("/")
async def get():
    return HTMLResponse("""
    <!DOCTYPE html>
    <html>
    <head>
        <title>Chat</title>
    </head>
    <body>
        <h1>WebSocket Chat</h1>
        <form action="" onsubmit="sendMessage(event)">
            <input type="text" id="messageText" autocomplete="off"/>
            <button>Send</button>
        </form>
        <ul id='messages'>
        </ul>
        <script>
            var ws = new WebSocket("ws://localhost:8000/ws");
            ws.onmessage = function(event) {
                var messages = document.getElementById('messages');
                var message = document.createElement('li');
                message.appendChild(document.createTextNode(event.data));
                messages.appendChild(message);
            };

            function sendMessage(event) {
                var input = document.getElementById("messageText");
                ws.send(input.value);
                input.value = '';
                event.preventDefault();
            }
        </script>
    </body>
    </html>
    """)

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)
登录后复制

前端(Streamlit)

  1. 安装依赖项:
pip install streamlit websocket-client
登录后复制
  1. 前端代码(frontend.py):
import streamlit as st
import asyncio
import threading
from websocket import create_connection, WebSocket

st.title("Real-time Messaging Application")

if 'messages' not in st.session_state:
    st.session_state.messages = []

def websocket_thread():
    ws = create_connection("ws://localhost:8000/ws")
    st.session_state.ws = ws
    while True:
        message = ws.recv()
        st.session_state.messages.append(message)
        st.experimental_rerun()

if 'ws' not in st.session_state:
    threading.Thread(target=websocket_thread, daemon=True).start()

input_message = st.text_input("Enter your message:")

if st.button("Send"):
    if input_message:
        st.session_state.ws.send(input_message)
        st.session_state.messages.append(f"You: {input_message}")

st.subheader("Chat Messages:")
for message in st.session_state.messages:
    st.write(message)
登录后复制

运行应用程序

  1. 启动FastAPI后端:
uvicorn backend:app
登录后复制
  1. 启动 Streamlit 前端:
streamlit run frontend.py
登录后复制

说明
后端(backend.py):

  • FastAPI 应用程序在 /ws 处有一个 WebSocket 端点。
  • ConnectionManager 处理 WebSocket 连接,向所有连接的客户端广播消息。
  • 根端点 (/) 提供一个简单的 HTML 页面来测试 WebSocket 连接。

前端(frontend.py):

  • Streamlit 应用程序连接到 WebSocket 服务器并侦听传入消息。
  • 一个单独的线程处理 WebSocket 连接,以防止阻塞 Streamlit 应用程序。
  • 用户可以通过输入框发送消息,消息会被发送到WebSocket服务器并显示在聊天中。

此示例演示了一个简单的实时消息应用程序,在后端使用 FastAPI 和 WebSockets,在前端使用 Streamlit。

以上是Python 中的同步和异步编程:关键概念和应用的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责声明 Sitemap
PHP中文网:公益在线PHP培训,帮助PHP学习者快速成长!