一个网站的建设需要哪些流程图,进出口代理公司,怎么学好网页设计,wordpress没有页脚选项CONTENTS 1. 同步与异步2. WebSocket3. 在JavaScript中使用WebSocket4. Django Channels 1. 同步与异步
在 Django 中#xff0c;同步和异步主要涉及到请求处理的方式。这两种方式的主要区别在于它们如何处理多个并发请求#xff1a;
同步#xff08;Synchronous#xff… CONTENTS 1. 同步与异步2. WebSocket3. 在JavaScript中使用WebSocket4. Django Channels 1. 同步与异步
在 Django 中同步和异步主要涉及到请求处理的方式。这两种方式的主要区别在于它们如何处理多个并发请求
同步Synchronous在同步模式下Django 会为每个请求创建一个单独的线程或进程。这意味着如果一个请求正在等待响应例如等待数据库查询返回结果那么整个线程或进程将被阻塞直到响应返回。这可能会导致资源的浪费因为在等待期间线程或进程不能做其他任何事情。异步Asynchronous与同步模式不同异步模式允许单个线程或进程同时处理多个请求。当一个请求需要等待响应时例如等待数据库查询返回结果线程或进程可以切换到另一个请求继续执行其他任务而不是被阻塞。这样可以更有效地利用系统资源提高并发处理能力。
Django 3.1 版本开始引入了对异步视图和中间件的支持这意味着你可以编写异步的视图函数这些函数可以使用 Python 的 async 和 await 关键字进行定义。这使得 Django 可以更好地处理 I/O 密集型任务如 HTTP 请求、数据库操作和文件读写等。
然而需要注意的是并非所有的 Django 组件都支持异步操作。例如Django 的 ORM对象关系映射目前仍然是同步的这意味着你不能在异步视图或中间件中直接使用它。如果你需要在异步代码中执行数据库操作你需要使用 Django 提供的 sync_to_async 或 async_to_sync 函数来确保数据库操作在同步环境中执行。
总的来说同步和异步各有优势和适用场景。对于 CPU 密集型任务同步模式可能更合适而对于 I/O 密集型任务异步模式可能会带来更好的性能。在实际开发中你可能需要根据应用的具体需求和性能要求来选择使用同步还是异步。
1同步代码样例
现在我们来看一些同步与异步的样例首先是同步视图在下面这个例子中当请求到达 sync_view 时Django 将等待视图函数完成后才会处理下一个请求
from django.http import HttpResponse
from django.shortcuts import renderdef sync_view(request): # 这是一个同步视图return HttpResponse(Hello, this is a synchronous view!)下面这个例子在视图中同步地从数据库获取所有的博客对象然后将它们传递给模板
from django.shortcuts import render
from .models import Blogdef sync_view(request):blogs Blog.objects.all() # 获取所有的博客对象return render(request, blog/index.html, {blogs: blogs})2异步代码样例
在下面这个例子中async_view 是一个异步视图。当请求到达这个视图时Django 可以在等待 asyncio.sleep(1) 完成时处理其他请求
import asyncio
from django.http import HttpResponseasync def async_view(request): # 这是一个异步视图await asyncio.sleep(1)return HttpResponse(Hello, this is an asynchronous view!)请注意要使用异步视图你需要确保你的 Django 项目正在运行在支持异步的 ASGI 服务器上而不是传统的 WSGI 服务器。此外你的中间件和任何你在视图中调用的代码也必须支持异步。否则你可能会遇到问题。如果你的代码库主要是同步的那么最好坚持使用同步视图。如果你正在编写新的、主要使用 Python 的异步库的代码那么异步视图可能会很有用。请记住混合使用同步和异步代码可以很复杂需要谨慎对待。
再来看下面的例子我们创建了一个新的 get_blogs 异步函数它使用 run_in_executor 方法在一个单独的线程中运行数据库查询。这允许 Django 在等待数据库查询完成时处理其他请求
import asyncio
from django.http import JsonResponse
from .models import Blogasync def async_view(request): # 异步获取所有的博客对象blogs await get_blogs()return JsonResponse({blogs: list(blogs.values())})async def get_blogs():loop asyncio.get_event_loop()blogs await loop.run_in_executor(None, Blog.objects.all)return blogs请注意虽然这个示例展示了如何在 Django 视图中使用异步代码操作数据库但是 Django 的数据库层目前还不支持原生的异步操作。因此在实践中你可能需要使用像 asgiref.sync_to_async 这样的工具来安全地在异步视图中执行同步数据库操作。同时你也需要确保你的数据库驱动程序和数据库服务器能够处理并发连接。否则你可能会遇到性能问题或错误。如果你不确定如何正确地使用异步代码那么最好使用同步视图和同步数据库操作。
2. WebSocket
WebSocket 是一种用于在 Web 和移动应用程序之间进行实时通信的新标准。WebSocket 设计为在 Web 浏览器和 Web 服务器之间实现但也可以由客户端或服务器应用程序使用。WebSocket 是一种提供单个 TCP 连接上的全双工通信通道的协议可以实现服务器和客户端之间的实时交互。
WebSocket 与 HTTP 不同其主要区别如下
通信方式HTTP 是单向的客户端发送请求服务器发送响应。而 WebSocket 是双向的在客户端-服务器通信的场景中使用的全双工协议即客户端和服务器可以同时发送和接收数据。连接HTTP 每次请求都需要重新建立连接而 WebSocket 使用长连接实现数据实时推送。一旦通信链接建立和连接打开后消息交换将以双向模式进行客户端-服务器之间的连接会持久存在。数据传输HTTP 协议中的数据传输是文本格式的而 WebSocket 可以传输文本和二进制数据。性能由于 HTTP 的每次请求都需要建立连接和断开连接而 WebSocket 可以在一次连接上进行多次通信因此 WebSocket 在性能上比 HTTP 有优势。应用场景HTTP 主要用于客户端和服务器之间的请求和响应如浏览器请求网页和服务器返回网页的 HTML 文件。WebSocket 可以实现双向通信常常用于实时通信场景。协议头HTTP 协议头的大小从200字节到2KB不等常见大小是700-800字节。而 WebSocket 协议头相对较小这使得其在高频率、小数据量的通信场景下更有优势。状态HTTP 是无状态协议而 WebSocket 是有状态协议。这意味着客户端和服务器之间的连接将保持活动状态直到被任何一方客户端或服务器终止。
两种协议都位于 OSI 模型的第七层并依赖于第四层的 TCP。尽管它们是不同的但 RFC 6455 指出WebSocket 旨在通过 HTTP 端口443和80工作并支持 HTTP 代理和中介从而使其与 HTTP 兼容。为了实现兼容性WebSocket 握手使用 HTTP Upgrade 头从 HTTP 协议切换到 WebSocket 协议。
WebSocket 协议使得 Web 浏览器或其他客户端应用程序和 Web 服务器之间可以在不需要客户端请求的情况下发送内容以及在保持连接打开的同时传递消息。这样客户端和服务器之间可以进行双向持续的对话。通信通常是通过 TCP 端口号443或80如果是非安全连接进行的这对于使用防火墙阻止非 Web Internet 连接的环境是有利的。
在 Django 中实现 WebSocket你可以选择使用 channels 或者 dwebsocket。但是channels 被更广泛地使用因为它可以完美地集成到 Django 的生态系统中。
3. 在JavaScript中使用WebSocket
1创建 WebSocket 对象
let ws new WebSocket(ws://localhost:8888); // 如果是安全连接则地址为wss://...2连接成功时的回调函数
当 WebSocket 连接成功时onopen 事件会被触发。你可以在这个函数中发送消息到服务器
ws.onopen function(params) {console.log(客户端连接成功);ws.send(hello); // 向服务器发送消息
};3从服务器接收信息时的回调函数
当从服务器接收到信息时onmessage 事件会被触发。你可以在这个函数中处理接收到的数据
ws.onmessage function(e) {console.log(收到服务器响应, e.data);
};4连接关闭时的回调函数
当连接关闭后onclose 事件会被触发。你可以在这个函数中处理连接关闭后的逻辑
ws.onclose function(e) {console.log(关闭客户端连接);
};5连接失败时的回调函数
ws.onerror function(e) {console.log(连接失败);
};6监听窗口关闭事件
当窗口关闭时主动去关闭 WebSocket 连接防止连接还没断开就关闭窗口这样服务端会抛异常
window.onbeforeunload function() {ws.close();
}4. Django Channels
Django Channels 是一个开源框架它扩展了 Django 的功能使得 Django 不仅可以处理 HTTP还可以处理需要长时间连接的协议如 WebSocket、MQTT消息队列遥测传输、聊天协议、广播等实时应用。
Channels 允许 Django 项目支持“长连接”它用 ASGI 替换了 Django 的默认 WSGI。ASGIAsynchronous Server Gateway Interface为异步 Python Web 服务器和应用程序提供了一个接口同时支持 WSGI 提供的所有功能。
Channels 保留了 Django 的同步行为并添加了一层异步协议允许用户编写完全同步、异步或两者混合的视图Views。Django Channels 提供了一种通信系统叫做 Channel Layer它可以让多个 Consumer 实例之间互相通信以及与外部 Django 程序实现互通。
Channel Layer 主要包括两种抽象概念Channel 和 Group。Channel 是一个发送消息的通道每个 Channel 都有一个名称拥有这个名称的人都可以往 Channel 里面发送消息。Group 是多个 Channel 的集合每个 Group 都有一个名称拥有这个名称的人都可以往这个 Group 里添加/删除 Channel也可以往 Group 里发送消息。Group 内的所有 Channel 都可以收到但是不能给 Group 内的具体某个 Channel 发送消息。使用 Django Channels 可以实现一些实时通讯的功能如在线聊天室、游戏、通知等。Consumer 是 Channels 的基本单位相当于 Django 的视图它是一个事件驱动的类可以处理不同类型的事件如连接、断开、接收消息等支持同步和异步应用程序。
现在我们来看一下 Django Channels 的样例首先需要安装 Channels 和 Channels Redis
pip install channels channels_redis然后需要在你的项目设置中settings.py 文件配置 CHANNEL_LAYERS 需要添加 channels 到你的 INSTALLED_APPS 列表并设置 ASGI_APPLICATION 和 CHANNEL_LAYERS。例如
INSTALLED_APPS [ channels, # 添加此行game.apps.GameConfig,django.contrib.admin,django.contrib.auth,django.contrib.contenttypes,django.contrib.sessions,django.contrib.messages,django.contrib.staticfiles,
]ASGI_APPLICATION djangoapp.asgi.application # djangoapp为你的项目名CHANNEL_LAYERS {default: {BACKEND: channels_redis.core.RedisChannelLayer,CONFIG: {hosts: [(127.0.0.1, 6379)],},},
}在这个例子中我们假设你正在本地运行一个 Redis 服务器它监听在6379端口。如果你的 Redis 服务器在其他地方或者使用了不同的端口你需要更新 hosts 设置。
接下来你需要在 Django App 的目录下创建一个路由文件 routing.py作用相当于 HTTP 的 urls并在其中定义你的 WebSocket 路由。我们先创建出来
from django.urls import pathwebsocket_urlpatterns [
]此外你还需要运行一个兼容的 ASGI 服务器如 Daphne 或 Uvicorn。我们安装 Daphne
pip install daphne输入 daphne 命令查看是否可用如果不可用说明应该是没有配置环境变量按如下方式修改环境变量需要重启系统
sudo vim /etc/environment
在 PATHxxx 后面添加 :/home/用户名/.local/bin
即: xxx:/home/用户名/.local/bin为了在 Django 项目中使用 Daphne你需要确保你的项目已经配置为使用 ASGI 而不是 WSGI。这通常意味着你需要在你的项目中创建一个 asgi.py 文件并在你的设置文件中设置 ASGI_APPLICATION 变量之前已经设置好了。
现在我们配置 djangoapp/djangoapp/asgi.py 文件
import osfrom channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
from game.routing import websocket_urlpatternsos.environ.setdefault(DJANGO_SETTINGS_MODULE, djangoapp.settings) # djangoapp为你的项目名application ProtocolTypeRouter({http: get_asgi_application(),websocket: AuthMiddlewareStack(URLRouter(websocket_urlpatterns))
})现在我们在 Django App 目录下创建 consumers.py
from channels.generic.websocket import AsyncWebsocketConsumer
import jsonclass ChatConsumer(AsyncWebsocketConsumer):async def connect(self):self.room_name self.scope[url_route][kwargs][room_name]self.room_group_name chat_%s % self.room_name# 加入房间await self.channel_layer.group_add(self.room_group_name,self.channel_name)await self.accept()async def disconnect(self, close_code):# 离开房间await self.channel_layer.group_discard(self.room_group_name,self.channel_name)# 接收来自WebSocket的消息async def receive(self, text_data):text_data_json json.loads(text_data)message text_data_json[message]# 发送消息到房间组await self.channel_layer.group_send(self.room_group_name,{type: chat_message,message: message})# 接收来自房间组的消息async def chat_message(self, event):message event[message]# 发送消息到WebSocketawait self.send(text_datajson.dumps({message: message}))在这个例子中我们创建了一个 ChatConsumer 类它是一个异步的 WebSocket Consumer这个类继承自 AsyncWebsocketConsumer这是 Django Channels 提供的一个基础类。
其中的主要函数说明如下
async def connect(self)当一个 WebSocket 连接打开时这个方法会被调用。在这个方法中我们从 URL 路由中获取房间名并将其保存在 self.room_name 中。然后我们创建一个房间组名并将其保存在 self.room_group_name 中。然后我们将当前的 Channel 添加到房间组中。最后我们接受 WebSocket 连接。async def disconnect(self, close_code)当一个 WebSocket 连接关闭时这个方法会被调用。在这个方法中我们将当前的 Channel 从房间组中移除。async def receive(self, text_data)当从 WebSocket 接收到消息时这个方法会被调用。在这个方法中我们首先将接收到的文本数据解析为 JSON然后我们从 JSON 数据中获取消息并将其发送到房间组中。async def chat_message(self, event)这是一个自定义的事件处理器方法当从房间组接收到类型为 chat_message 的事件时这个方法会被调用。在这个方法中我们首先从事件中获取消息然后我们将消息发送回 WebSocket。
总的来说这段代码的功能为当用户连接到 WebSocket 时他们会被添加到一个名为 chat_{room_name} 的组中。当他们发送消息时这个消息会被广播到他们所在的组中的所有其他用户。当他们接收到组中的消息时这个消息会被发送回他们的 WebSocket即实现了一个简单的聊天室功能。
最后我们定义一下 Consumer 的路由以下代码将 URL 路径 ws/chat/{room_name}/ 映射到我们的 ChatConsumer。这意味着当用户连接到这个路径的 WebSocket 时他们会被连接到聊天室
from django.urls import re_path
from .consumers import ChatConsumerwebsocket_urlpatterns [re_path(rws/chat/(?Proom_name\w)/$, ChatConsumer.as_asgi()),
]