翻译DjangoChannels官方文档Tutorial守护窗明守护爱

ChannelsallowsyoutouseWebSocketsandothernon-HTTPprotocolsinyourDjangosite.ForexampleyoumightwanttouseWebSocketstoallowapageonyoursitetoimmediatelyreceiveupdatesfromyourDjangoserverwithoutusingHTTPlong-pollingorotherexpensivetechniques.Channels允许您在Django站点中使用Websockets和其他非HTTP协议。例如,您可能希望Websockets允许网站上的页面立即从Django服务器接收更新,而无需使用HTTP长轮询或其他昂贵的技术。

Inthistutorialwewillbuildasimplechatserver,whereyoucanjoinanonlineroom,postmessagestotheroom,andhaveothersinthesameroomseethosemessagesimmediately.在本教程中,我们将建立一个简单的聊天服务器,在那里你可以加入一个在线房间,张贴消息到房间,并让其他人在同一房间看到这些消息立即。

Inthistutorialwewillbuildasimplechatserver.Itwillhavetwopages:在本教程中,我们将构建一个简单的聊天服务器。它将有两个页面:

TheroomviewwilluseaWebSockettocommunicatewiththeDjangoserverandlistenforanymessagesthatareposted.房间视图将使用WebSocket与Django服务器进行通信,并监听任何发送出来的消息。

WeassumethatyouarefamilarwithbasicconceptsforbuildingaDjangosite.IfnotwerecommendyoucompletetheDjangotutorialfirstandthencomebacktothistutorial.我们假设您熟悉构建Django站点的基本概念。如果不是,我们建议您先完成Django教程,然后再回到本教程。

WeassumethatyouhaveDjangoinstalledalready.YoucantellDjangoisinstalledandwhichversionbyrunningthefollowingcommandinashellprompt(indicatedbythe$prefix):我们假设你已经安装了Django。您可以通过在shell提示符下运行以下命令(用$前缀表示)来查看您安装的Django版本:

$python3-mdjango--versionWealsoassumethatyouhaveChannelsinstalledalready.YoucantellChannelsisinstalledbyrunningthefollowingcommand:我们还假设您已经安装了Channels。您可以通过运行以下命令来查看Channels安装与否:

$python3-c'importchannels;print(channels.__version__)'ThistutorialiswrittenforChannels2.0,whichsupportsPython3.5+andDjango1.11+.IftheChannelsversiondoesnotmatch,youcanrefertothetutorialforyourversionofChannelsbyusingtheversionswitcheratthebottomleftcornerofthispage,orupdateChannelstothenewestversion.本教程是为Channels2.0编写的,它支持Python3.5+和Django1.11+。如果Channels版本不匹配,你可以使用本页左下角的版本切换器,或将Channels更新到最新版本,以参考您的Channels版本的教程。

ThistutorialalsousesDockertoinstallandrunRedis.WeuseRedisasthebackingstoreforthechannellayer,whichisanoptionalcomponentoftheChannelslibrarythatweuseinthetutorial.InstallDockerfromitsofficialwebsite-thereareofficialruntimesforMacOSandWindowsthatmakeiteasytouse,andpackagesformanyLinuxdistributionswhereitcanrunnatively.本教程还使用Docker安装和运行Redis。我们使用Redis作为Channels层的后备存储,它是我们在教程中使用的Channels库的可选组件。从其官方网站安装Docker--有用于MacOS和Windows的易于使用的正式运行版,并为许多Linux发行版提供了可本地运行的软件包。

Note提醒WhileyoucanrunthestandardDjangorunserverwithouttheneedforDocker,thechannelsfeatureswe’llbeusinginlaterpartsofthetutorialwillneedRedistorun,andwerecommendDockerastheeasiestwaytodothis.虽然您可以运行标准的Djangorunserver不需要Docker,我们将使用的channels功能在后面的教程将需要Redis运行,我们建议使用Docker这一最简单的方式来做到这一点。

Ifyoudon’talreadyhaveaDjangoproject,youwillneedtocreateone.如果您还没有Django项目,您将需要创建一个。

Fromthecommandline,cdintoadirectorywhereyou’dliketostoreyourcode,thenrunthefollowingcommand:从命令行,将cd放入要存储代码的目录中,然后运行以下命令:

$django-adminstartprojectmysiteThiswillcreateamysitedirectoryinyourcurrentdirectorywiththefollowingcontents:这将在当前目录中创建一个mysite目录,其中有以下内容:

mysite/manage.pymysite/__init__.pysettings.pyurls.pywsgi.pyCreatingtheChatapp创建聊天应用程序Wewillputthecodeforthechatserverinitsownapp.我们会将聊天服务器的代码放在它自己的应用程序中。

Makesureyou’reinthesamedirectoryasmanage.pyandtypethiscommand:请确保您位于与manage.py相同的目录中.然后输入以下命令:

$python3manage.pystartappchatThat’llcreateadirectorychat,whichislaidoutlikethis:这将创建一个chat文件夹,它是像这样的:

chat/__init__.pyadmin.pyapps.pymigrations/__init__.pymodels.pytests.pyviews.pyForthepurposesofthistutorial,wewillonlybeworkingwithchat/views.pyandchat/__init__.py.Soremoveallotherfilesfromthechatdirectory.为了达到本教程的目的,我们将只使用chat/views.py和chat/__init__.py。因此,从chat目录中删除所有其他文件。

Afterremovingunnecessaryfiles,thechatdirectoryshouldlooklike:删除不必要的文件后,chat目录应如下所示:

chat/__init__.pyviews.pyWeneedtotellourprojectthatthechatappisinstalled.Editthemysite/settings.pyfileandadd'chat'totheINSTALLED_APPSsetting.It’lllooklikethis:我们需要告诉我们的项目chatapp已经安装。编辑mysite/settings.py文件并将'chat'添加到INSTALLED_APPS设置中。它看起来像这样:

#mysite/settings.pyINSTALLED_APPS=['chat','django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles',]Addtheindexview添加index视图Wewillnowcreatethefirstview,anindexviewthatletsyoutypethenameofachatroomtojoin.现在,我们将创建第一个视图,这个index视图允许您输入要加入的聊天室的名称。

Createatemplatesdirectoryinyourchatdirectory.Withinthetemplatesdirectoryyouhavejustcreated,createanotherdirectorycalledchat,andwithinthatcreateafilecalledindex.htmltoholdthetemplatefortheindexview.在chat目录中创建templates目录。在刚刚创建的templates目录中,创建另一个名为chat的目录,并在其中创建一个名为index.html的文件。

Yourchatdirectoryshouldnowlooklike:您的chat目录现在应该看起来像:

chat/__init__.pytemplates/chat/index.htmlviews.pyPutthefollowingcodeinchat/templates/chat/index.html:将下面的代码写进chat/templates/chat/index.html文件中:

ChatRoomsWhatchatroomwouldyouliketoenter

Createtheviewfunctionfortheroomview.Putthefollowingcodeinchat/views.py:为room视图创建视图函数。将下面的代码写进chat/views.py文件中:

#chat/views.pyfromdjango.shortcutsimportrenderdefindex(request):returnrender(request,'chat/index.html',{})Tocalltheview,weneedtomapittoaURL-andforthisweneedaURLconf.为了调用这个视图,我们需要把它映射到一个URL--因此我们需要一个URL配置文件。

TocreateaURLconfinthechatdirectory,createafilecalledurls.py.Yourappdirectoryshouldnowlooklike:为了在chat目录下创建一个URL配置文件,我们需要新建一个名为urls.py的文件。你的app目录应该像现在这样子:

chat/__init__.pytemplates/chat/index.htmlurls.pyviews.pyInthechat/urls.pyfileincludethefollowingcode:在chat/urls.py文件中包含以下代码:

#chat/urls.pyfromdjango.conf.urlsimporturlfrom.importviewsurlpatterns=[url(r'^$',views.index,name='index'),]ThenextstepistopointtherootURLconfatthechat.urlsmodule.Inmysite/urls.py,addanimportfordjango.conf.urls.includeandinsertaninclude()intheurlpatternslist,soyouhave:下一步是将根目录下的URLconf文件指向chat.urls模块。在mysite/urls.py中,导入django.conf.urls.include模块,并在urlpatterns列表中插入一个include()函数,因此您需要写入以下代码:

#mysite/urls.pyfromdjango.conf.urlsimportinclude,urlfromdjango.contribimportadminurlpatterns=[url(r'^chat/',include('chat.urls')),url(r'^admin/',admin.site.urls),]Let’sverifythattheindexviewworks.Runthefollowingcommand:让我们验证index视图是否有效。运行以下命令:

$python3manage.pyrunserverYou’llseethefollowingoutputonthecommandline:您将在命令行中看到以下输出:

GototheterminalwhereyourantherunservercommandandpressControl-Ctostoptheserver.转到运行runserver命令的终端,然后按下Control+C以停止服务器。

Sofarwe’vejustcreatedaregularDjangoapp;wehaven’tusedtheChannelslibraryatall.Nowit’stimetointegrateChannels.到目前为止,我们刚刚创建了一个常规的Django应用程序;我们根本就没有使用Channels库。现在是时候集成Channels库了。

Let’sstartbycreatingarootroutingconfigurationforChannels.AChannelsroutingconfigurationissimilartoaDjangoURLconfinthatittellsChannelswhatcodetorunwhenanHTTPrequestisreceivedbytheChannelsserver.让我们从创建Channels的根路由配置文件开始。Channels路由配置类似于DjangoURLconf,它会告诉Channels当收到由Channels服务器发过来的HTTP请求时,应该执行什么代码。

We’llstartwithanemptyroutingconfiguration.Createafilemysite/routing.pyandincludethefollowingcode:我们将从一个空的路由配置文件开始。创建文件mysite/routing.py,并写入以下代码:

#mysite/settings.pyINSTALLED_APPS=['channels','chat','django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles',]You’llalsoneedtopointChannelsattherootroutingconfiguration.Editthemysite/settings.pyfileagainandaddthefollowingtothebottomofit:您同样需要在根路由配置中指向Channels。再次编辑mysite/settings.py文件,并将以下内容添加到底部:

#mysite/settings.py#ChannelsASGI_APPLICATION='mysite.routing.application'WithChannelsnowintheinstalledapps,itwilltakecontroloftherunservercommand,replacingthestandardDjangodevelopmentserverwiththeChannelsdevelopmentserver.现在已安装的应用程序中有Channels,它将控制runserver命令,用Channels开发服务器替换标准的Django开发服务器。

Note提醒

TheChannelsdevelopmentserverwillconflictwithanyotherthird-partyappsthatrequireanoverloadedorreplacementrunservercommand.Anexampleofsuchaconflictiswithwhitenoise.runserver_nostaticfromwhitenoise.Inordertosolvesuchissues,trymovingchannelstothetopofyourINSTALLED_APPSorremovetheoffendingappaltogether.Channels开发服务器将与需要重载或替换runserver命令的任何其他第三方应用程序冲突。whitenoise中的whitenoise.runserver_nostatic是一个冲突的例子。为了解决这些问题,请尝试将Channels移动到您的INSTALLED_APPS的顶部,或者完全删除与其发生冲突的应用程序。

Let’sensurethattheChannelsdevelopmentserverisworkingcorrectly.Runthefollowingcommand:让我们确保Channels开发服务器工作正常。运行以下命令:

Ignorethewarningaboutunapplieddatabasemigrations.Wewon’tbeusingadatabaseinthistutorial.忽略有关未应用数据库迁移的警告。我们将不会在本教程中使用数据库。

ThistutorialbeginswhereTutorial1leftoff.We’llgettheroompageworkingsothatyoucanchatwithyourselfandothersinthesameroom.本教程在教程1的基础上开始。我们会让房间页面工作,这样你可以和你自己或者其他人在同一个房间里聊天。

Wewillnowcreatethesecondview,aroomviewthatletsyouseemessagespostedinaparticularchatroom.现在,我们将创建第二个视图,即一个允许您查看在特定聊天室中发布消息的房间视图。

Createanewfilechat/templates/chat/room.html.Yourappdirectoryshouldnowlooklike:创建新的文件chat/templates/chat/room.html。您的应用程序目录现在应该看起来像:

chat/__init__.pytemplates/chat/index.htmlroom.htmlurls.pyviews.pyCreatetheviewtemplatefortheroomviewinchat/templates/chat/room.html:在chat/templates/chat/room.html中填入一下代码:

#chat/views.pyfromdjango.shortcutsimportrenderfromdjango.utils.safestringimportmark_safeimportjsondefindex(request):returnrender(request,'chat/index.html',{})defroom(request,room_name):returnrender(request,'chat/room.html',{'room_name_json':mark_safe(json.dumps(room_name))})Createtheroutefortheroomviewinchat/urls.py:在chat/urls.py中创建房间视图的路由:

#chat/urls.pyfromdjango.conf.urlsimporturlfrom.importviewsurlpatterns=[url(r'^$',views.index,name='index'),url(r'^(P[^/]+)/$',views.room,name='room'),]StarttheChannelsdevelopmentserver:启动Channels开发服务器:

Typethemessage“hello”andpressenter.Nothinghappens.Inparticularthemessagedoesnotappearinthechatlog.Why键入消息"hello",然后按enter键。什么也没有发生。尤其是,消息并不会出现在聊天日志中。为什么?

TheroomviewistryingtoopenaWebSockettotheURLws://127.0.0.1:8000/ws/chat/lobby/butwehaven’tcreatedaconsumerthatacceptsWebSocketconnectionsyet.Ifyouopenyourbrowser’sJavaScriptconsole,youshouldseeanerrorthatlookslike:房间视图试图打开一个WebSocket连接到URLws://127.0.0.1:8000/ws/chat/lobby/,但我们还没有创建一个接受WebSocket连接的consumer。如果打开浏览器的JavaScript控制台,您应该会看到如下所示的错误:

WebSocketconnectionto'ws://127.0.0.1:8000/ws/chat/lobby/'failed:Unexpectedresponsecode:500Writeyourfirstconsumer编写您的第一个用户WhenDjangoacceptsanHTTPrequest,itconsultstherootURLconftolookupaviewfunction,andthencallstheviewfunctiontohandletherequest.Similarly,whenChannelsacceptsaWebSocketconnection,itconsultstherootroutingconfigurationtolookupaconsumer,andthencallsvariousfunctionsontheconsumertohandleeventsfromtheconnection.当Django接受HTTP请求时,它会根据根URLconf以查找视图函数,然后调用视图函数来处理请求。同样,当Channels接受WebSocket连接时,它会根据根路由配置以查找对应的consumer,然后调用consumer上的各种函数来处理来自这个连接的事件。

WewillwriteabasicconsumerthatacceptsWebSocketconnectionsonthepath/ws/chat/ROOM_NAME/thattakesanymessageitreceivesontheWebSocketandechositbacktothesameWebSocket.我们将编写一个简单的consumer,它会在路径/ws/chat/ROOM_NAME/接收WebSocket连接,然后把接收任意的消息,回送给同一个WebSocket连接。

Itisgoodpracticetouseacommonpathprefixlike/ws/todistinguishWebSocketconnectionsfromordinaryHTTPconnectionsbecauseitwillmakedeployingChannelstoaproductionenvironmentincertainconfigurationseasier.使用常见的路径前缀(如/ws)来区分WebSocket连接与普通HTTP连接是很好的做法,因为它将使在某些配置中部署Channels更容易。

Inparticularforlargesitesitwillbepossibletoconfigureaproduction-gradeHTTPserverlikenginxtorouterequestsbasedonpathtoeitheraproduction-gradeWSGIserverlikeGunicorn+DjangoforordinaryHTTPrequestsoraproduction-gradeASGIserverlikeDaphne+ChannelsforWebSocketrequests.特别是大型网站,它们很有可能配置像nginx这样的生产级别HTTP服务器,根据路径将请求发送到生产级别的WSGI服务器,例如用于处理普通HTTP请求的Gunicorn+Django,或生产级别的ASGI服务器,例如用于处理WebSocket请求的Daphne+Channels。

NotethatforsmallersitesyoucanuseasimplerdeploymentstrategywhereDaphneservesallrequests-HTTPandWebSocket-ratherthanhavingaseparateWSGIserver.Inthisdeploymentconfigurationnocommonpathprefixlikeis/ws/isnecessary.请注意,对于较小的站点,您可以使用更简单的部署策略,其中Daphne服务器处理所有的请求--HTTP和WebSocket--而不是单独的WSGI服务器。在这种部署配置策略中,不需要使用/ws/这样的通用路径前缀。

Createanewfilechat/consumers.py.Yourappdirectoryshouldnowlooklike:创建新文件chat/consumers.py。您的应用程序目录现在应该看起来像:

chat/__init__.pyconsumers.pytemplates/chat/index.htmlroom.htmlurls.pyviews.pyPutthefollowingcodeinchat/consumers.py:在chat/consumers.py中写入以下代码:

#chat/consumers.pyfromchannels.generic.websocketimportWebsocketConsumerimportjsonclassChatConsumer(WebsocketConsumer):defconnect(self):self.accept()defdisconnect(self,close_code):passdefreceive(self,text_data):text_data_json=json.loads(text_data)message=text_data_json['message']self.send(text_data=json.dumps({'message':message}))ThisisasynchronousWebSocketconsumerthatacceptsallconnections,receivesmessagesfromitsclient,andechosthosemessagesbacktothesameclient.Fornowitdoesnotbroadcastmessagestootherclientsinthesameroom.这是一个同步WebSocketconsumer,它接受所有连接,接收来自其客户端的消息,并将这些消息回送到同一客户端。现在,它不向同一个房间的其他客户端广播消息。

Channelsalsosupportswritingasynchronousconsumersforgreaterperformance.Howeveranyasynchronousconsumermustbecarefultoavoiddirectlyperformingblockingoperations,suchasaccessingaDjangomodel.SeetheConsumersreferenceformoreinformationaboutwritingasynchronousconsumers.Channels还支持编写异步consumers以提高性能。但是,任何异步consumers都必须小心,避免直接执行阻塞操作,例如访问Django的model。有关编写异步consumers的详细信息,请参阅Consumers。

Weneedtocreatearoutingconfigurationforthechatappthathasaroutetotheconsumer.Createanewfilechat/routing.py.Yourappdirectoryshouldnowlooklike:我们需要为chatapp创建一个路由配置,它有一个通往consumer的路由。创建新文件chat/routing.py。您的应用程序目录现在应该看起来像:

chat/__init__.pyconsumers.pyrouting.pytemplates/chat/index.htmlroom.htmlurls.pyviews.pyPutthefollowingcodeinchat/routing.py:在chat/routing.py中输入以下代码:

#chat/routing.pyfromdjango.conf.urlsimporturlfrom.importconsumerswebsocket_urlpatterns=[url(r'^ws/chat/(P[^/]+)/$',consumers.ChatConsumer),]Thenextstepistopointtherootroutingconfigurationatthechat.routingmodule.Inmysite/routing.py,importAuthMiddlewareStack,URLRouter,andchat.routing;andinserta'websocket'keyintheProtocolTypeRouterlistinthefollowingformat:下一步是将根路由指向chat.routing模块。在mysite/routing.py中,导入AuthMiddlewareStack、URLRouter和chat.routing;并在ProtocolTypeRouter列表中插入一个"websocket"键,格式如下:

TheAuthMiddlewareStackwillpopulatetheconnection’sscopewithareferencetothecurrentlyauthenticateduser,similartohowDjango’sAuthenticationMiddlewarepopulatestherequestobjectofaviewfunctionwiththecurrentlyauthenticateduser.(Scopeswillbediscussedlaterinthistutorial.)ThentheconnectionwillbegiventotheURLRouter.AuthMiddlewareStack将使用对当前经过身份验证的用户的引用来填充连接的scope,类似于Django的AuthenticationMiddleware用当前经过身份验证的用户填充视图函数的请求对象。(Scopes将在本教程后面讨论。)然后连接将被给到URLRouter。

TheURLRouterwillexaminetheHTTPpathoftheconnectiontorouteittoaparticularconsumer,basedontheprovidedurlpatterns.根据提供的url模式,URLRouter将检查连接的HTTP路径,以将其路由指定到到特定的consumer。

Let’sverifythattheconsumerforthe/ws/chat/ROOM_NAME/pathworks.StarttheChannelsdevelopmentserver:让我们验证consumer的/ws/chat/ROOM_NAME/路径是否工作。启动Channels开发服务器:

Typethemessage“hello”andpressenter.Youshouldnowsee“hello”echoedinthechatlog.输入消息"hello",然后按enter键。您现在应该看到"hello"在聊天日志中显示。

Achannellayerisakindofcommunicationsystem.Itallowsmultipleconsumerinstancestotalkwitheachother,andwithotherpartsofDjango.channellayer是一种通信系统。它允许多个consumer实例互相交谈,以及与Django的其他部分进行通信。

Achannellayerprovidesthefollowingabstractions:channellayer提供以下抽象:

Everyconsumerinstancehasanautomaticallygenerateduniquechannelname,andsocanbecommunicatedwithviaachannellayer.每个consumer实例都有一个自动生成的唯一的channel名称,因此可以通过channellayer进行通信。

InourchatapplicationwewanttohavemultipleinstancesofChatConsumerinthesameroomcommunicatewitheachother.TodothatwewillhaveeachChatConsumeradditschanneltoagroupwhosenameisbasedontheroomname.ThatwillallowChatConsumerstotransmitmessagestoallotherChatConsumersinthesameroom.在我们的聊天应用程序中,我们希望在同一房间中有多个ChatConsumer的实例相互通信。要做到这一点,我们将有每个ChatConsumer添加它的channel到一个group,其名称是基于房间的名称。这将允许ChatConsumers将消息传输到同一个房间中的所有其他ChatConsumers。

WewilluseachannellayerthatusesRedisasitsbackingstore.TostartaRedisserveronport6379,runthefollowingcommand:我们将使用一个channellayer,使用Redis作为其后备存储。要在端口6379上启动Redis服务器,请运行以下命令:

$dockerrun-p6379:6379-dredis:2.8Weneedtoinstallchannels_redissothatChannelsknowshowtointerfacewithRedis.Runthefollowingcommand:我们需要安装channels_redis,以便Channels知道如何调用redis。运行以下命令:

$pip3installchannels_redisBeforewecanuseachannellayer,wemustconfigureit.Editthemysite/settings.pyfileandaddaCHANNEL_LAYERSsettingtothebottom.Itshouldlooklike:在使用channellayer之前,必须对其进行配置。编辑mysite/settings.py文件并将CHANNEL_LAYERS设置添加到底部。它应该看起来像:

#mysite/settings.py#ChannelsASGI_APPLICATION='mysite.routing.application'CHANNEL_LAYERS={'default':{'BACKEND':'channels_redis.core.RedisChannelLayer','CONFIG':{"hosts":[('127.0.0.1',6379)],},},}Note提醒

Itispossibletohavemultiplechannellayersconfigured.Howevermostprojectswilljustuseasingle'default'channellayer.可以配置多个channellayer。然而,大多数项目只使用一个"默认"的channellayer。

Let’smakesurethatthechannellayercancommunicatewithRedis.OpenaDjangoshellandrunthefollowingcommands:让我们确保channellayer可以与Redis通信。打开Djangoshell并运行以下命令:

$python3manage.pyshell>>>importchannels.layers>>>channel_layer=channels.layers.get_channel_layer()>>>fromasgiref.syncimportasync_to_sync>>>async_to_sync(channel_layer.send)('test_channel',{'type':'hello'})>>>async_to_sync(channel_layer.receive)('test_channel'){'type':'hello'}TypeControl-DtoexittheDjangoshell.输入Control+D退出Djangoshell。

Nowthatwehaveachannellayer,let’suseitinChatConsumer.Putthefollowingcodeinchat/consumers.py,replacingtheoldcode:现在我们有了一个channellayer,让我们在ChatConsumer中使用它。将以下代码放在chat/consumers.py中,替换旧代码:

SeveralpartsofthenewChatConsumercodedeservefurtherexplanation:新的ChatConsumer代码中有几个部分需要进一步解释:

Let’sverifythatthenewconsumerforthe/ws/chat/ROOM_NAME/pathworks.TostarttheChannelsdevelopmentserver,runthefollowingcommand:让我们验证新consumer的/ws/chat/ROOM_NAME/路径是否工作。要启动Channels开发服务器,请运行以下命令:

Inthesecondbrowsertab,typethemessage“hello”andpressenter.Youshouldnowsee“hello”echoedinthechatloginboththesecondbrowsertabandinthefirstbrowsertab.在第二个浏览器选项卡中,输入消息"hello",然后按enter键。在第二个浏览器选项卡和第一个浏览器选项卡中,您现在应该看到"hello"在聊天日志中显示。

Younowhaveabasicfully-functionalchatserver!您现在有一个基本的功能齐全的聊天服务器!

ThistutorialbeginswhereTutorial2leftoff.We’llrewritetheconsumercodetobeasynchronousratherthansynchronoustoimproveitsperformance.本教程在教程2的基础上开始。我们将重写consumer代码使其变成是异步的而不是同步的,以提高其性能。

TheChatConsumerthatwehavewritteniscurrentlysynchronous.SynchronousconsumersareconvenientbecausetheycancallregularsynchronousI/OfunctionssuchasthosethataccessDjangomodelswithoutwritingspecialcode.Howeverasynchronousconsumerscanprovideahigherlevelofperformancesincetheydon’tneedcreateadditionalthreadswhenhandlingrequests.我们编写的ChatConsumer当前是同步的。同步的consumers很方便,因为它们可以调用常规的同步I/O函数,例如访问Djangomodels而不用编写特殊的代码。但是,异步的consumers可以提供更高级别的性能,因为它们在处理请求时不需要创建其他线程。

ChatConsumeronlyusesasync-nativelibraries(Channelsandthechannellayer)andinparticularitdoesnotaccesssynchronousDjangomodels.Thereforeitcanberewrittentobeasynchronouswithoutcomplications.ChatConsumer只使用async-native库(Channels和channellayer),特别是它不访问同步的Djangomodels。因此,它可以被改写为异步的而不会变得复杂化。

EvenifChatConsumerdidaccessDjangomodelsorothersynchronouscodeitwouldstillbepossibletorewriteitasasynchronous.Utilitieslikeasgiref.sync.sync_to_asyncandchannels.db.database_sync_to_asynccanbeusedtocallsynchronouscodefromanasynchronousconsumer.Theperformancegainshoweverwouldbelessthanifitonlyusedasync-nativelibraries.即使ChatConsumer访问Djangomodels或其他同步的代码,它仍然可以将其重写为异步的。像asgiref.sync.sync_to_async和channels.db.database_sync_to_async这样的实用工具可以用来从异步consumer那里调用同步的代码。但是,性能增益将小于仅使用async-native库的方式。

Let’srewriteChatConsumertobeasynchronous.Putthefollowingcodeinchat/consumers.py:让我们重写ChatConsumer使其变为异步的。在chat/consumers.py中输入以下代码:

Let’sverifythattheconsumerforthe/ws/chat/ROOM_NAME/pathstillworks.TostarttheChannelsdevelopmentserver,runthefollowingcommand:让我们验证consumer的/ws/chat/ROOM_NAME/路径是否仍然有效。启动Channels开发服务器,运行以下命令:

Nowyourchatserverisfullyasynchronous!现在,您的聊天服务器是完全异步的了!

ThistutorialbeginswhereTutorial3leftoff.We’vebuiltasimplechatserverandnowwe’llcreatesomeautomatedtestsforit.本教程在教程3的基础上开始。我们已经建立了一个简单的聊天服务器,现在我们将为它创建一些自动化测试。

Toensurethatthechatserverkeepsworking,wewillwritesometests.为了确保聊天服务器能够继续工作,我们将编写一些测试。

Wewillwriteasuiteofend-to-endtestsusingSeleniumtocontrolaChromewebbrowser.Thesetestswillensurethat:我们将编写一套端到端的测试,使用Selenium来控制Chromeweb浏览器。这些测试将确保:

InstalltheChromewebbrowser,ifyoudonotalreadyhaveit.如果您尚未拥有Chromeweb浏览器,请安装它。

Installchromedriver.安装chromedriver。

InstallSelenium.Runthefollowingcommand:安装Selenium。运行以下命令:

$pip3installseleniumCreateanewfilechat/tests.py.Yourappdirectoryshouldnowlooklike:创建新的文件chat/tests.py。您的应用程序目录现在应该看起来像:

chat/__init__.pyconsumers.pyrouting.pytemplates/chat/index.htmlroom.htmltests.pyurls.pyviews.pyPutthefollowingcodeinchat/tests.py:在chat/tests.py中输入以下代码:

Torunthetests,runthefollowingcommand:要运行测试,请运行以下命令:

$python3manage.pytestchat.testsYoushouldseeoutputthatlookslike:您应该看到如下所示的输出:

Creatingtestdatabaseforalias'default'...Systemcheckidentifiednoissues(0silenced)...----------------------------------------------------------------------Ran2testsin5.014sOKDestroyingtestdatabaseforalias'default'...Younowhaveatestedchatserver!你现在有一个经过测试的聊天服务器了!

What’snext接下来应该做什么呢?

Congratulations!You’vefullyimplementedachatserver,madeitperformantbywritingitinasynchronousstyle,andwrittenautomatedteststoensureitwon’tbreak.祝贺!您已经完全实现了一个聊天服务器,通过在异步样式中编写它来高性能,并编写了自动测试以确保它不会中断。

Thisistheendofthetutorial.AtthispointyoushouldknowenoughtostartanappofyourownthatusesChannelsandstartfoolingaround.Asyouneedtolearnnewtricks,comebacktorestofthedocumentation.这是教程的结尾。现在,你应该清楚地知道如何启动一个使用了Channels的你自己的应用程序和做其他的操作。当您需要学习新的技巧时,请回到文档的其余部分。

THE END
1.管理库MicrosoftLearn重写环境库路径并将其设置为 dir。 有关详细信息,请参阅 LINK /LIBPATH 选项的说明。/LIST 将有关输出库的信息显示到标准输出。 可以将输出重定向到某个文件。 可以使用 /LIST 来确定现有库的内容,无需修改它。/NAME: filename 当生成导入库时,filename 指定正在为其生成导入库的 DLL 的名称。/https://docs.microsoft.com/zh-CN/cpp/build/reference/managing-a-library?view=msvc-140
2.assembly怎么指定lib只包含某一个环境下的lib作为一个初学者,整了一下午才弄明白,在这里写出来分享给像我一样的初学者 C#的Assembly.Load.CreateInstance是C#反射机制的一部分因为论坛上有个人问了个类似的问题,然后之前看设计模式上还提到了这个,当时没弄明白而且还可耻的误导了。。。 C#的Assembly.Load.CreateInstance方法的使用是这样的: https://blog.51cto.com/u_14120/12793077
3.静态库的建立cmake配置静态库当我们想要保护自己的代码而不被其他人看到源代码,并能让其他人使用的时候,这个时候就需要将自己的代码建立成静态库文件(.lib文件)。当我们把.lib文件发给对方后,他就可以调用并正常使用。 二、如何建立静态库文件 以VS2019为例子 步骤:建立新项目-->建立源文件-->建立.h头文件-->将项目设置为静态库 https://blog.csdn.net/2402_88991786/article/details/144385969
4.如何创建Android库以及掌握.aar文件的使用技巧?4、修改build.gradle文件:打开库模块的build.gradle文件,确保插件设置为com.android.library,而不是com.android.application,这是将模块识别为库的关键。 5、同步项目:点击Sync Project with Gradle Files按钮,确保所有更改生效。 6、编译AAR文件:在Gradle窗口中,选择assembleRelease或assembleDebug任务,编译成功后,可以在https://www.kdun.com/ask/1395108.html
5.Eclipse中自定义Library时选中Systemlibraries是如何使用的具体是:菜单 Window ==> Preferences ==>Java==> Build Path ==> User Libraries ==> New ==> System library(added to the boot class path) 打上勾后变成System libraries,如何使用呢?与不打勾有何区别?作用是什么? 创建前我们可以看提示是说:System libraries will be added to the boot class pathhttps://cloud.tencent.com/developer/article/1396720
6.SDL入门教程(一):2VisualC++下的安装与设置SDL入门教程(一):2、Visual C++ 下的安装与设置 作者:龙飞 2.1:获得Visual C++ 2008 Express Edition。 使用盗版不是一个好习惯。与其背上贼名,我更愿意放弃华丽的外表,使用朴实无华的免费软件。你可能知道Linux和GNU,但是也许你还不知道$M也提供一些“免费的午餐”。Visual Studio 的Edition版本就是这样的一种http://www.cppblog.com/lf426/archive/2008/01/31/42289.html
7.vray材质库(.mat文件)使用教程含贴图设置教程.pdf关闭预览 想预览更多内容,点击免费在线预览全文 免费在线预览全文 vray材质库(*.mat文件)使用教程-含贴图设置教程 准备工作: A、将材质文件(.mat文件)拷贝到max安装目录下的“materiallibraries”文件夹中 B、将贴图(图片)拷贝到max安装目录下的“maps”文件夹中(可以在maps文件夹 下新建一个目录 如:“Archshadershttps://max.book118.com/html/2021/1129/8043102106004046.shtm
8.STM32CubeMX系列教程06本教程由作者strongerHuang于2019年03月原创发布。 标签:STM32、 STM32CubeMX、 LL库、 HAL库 版权所有:禁止商用 申明:该文档仅供个人学习使用,转载请公众号联系作者授权。 1写在前面 STM32CubeMX的Project Manager工程管理器包含:Project工程管理、 Code Generator代码生成、 Advanced Settings高级设置三部分内容。 https://www.wxworm.com/article/61328.html
9.[GD32小白笔记1]创建GD32F4xx的模板工程工程设置配置 后记 前言 笔者之前主要是学习STM32,近期由于朋友工作需要,询问GD32相关事宜,想着国产芯片可以学习一下,于是开始记录学习的笔记。 主要还是使用keil进行学习 安装必要工具 Keil安装教程就不赘述了,许多教程写得很明确了。 下载芯片对应固件包和支持包 笔者使用的是单片机GD32F405RG,使用搜索引擎便可以快速https://zhuanlan.zhihu.com/p/684136520
10.vray材质库使用教程含贴图设置教程3.选择材质库 4.打开你下载的.mat文件(找到max根目录中“materiallibraries”文件夹下的材质文件)4.https://www.3d66.com/changjianwenti/tiwen_73203.html
11.SketchLibraries功能图文详解Mac教程团队作战的设计师们则可以充分利用Libraries的同步能力来确保设计方案中的UI元素属于最新版本,或是及时获取最新的品牌风格定义。Libraries被隔离于工作文件之外,你可以通过其存放媒介所提供的安全策略设置来确保其不会被错误的变更;对于任何升级变更,你也有机会在同步之前对其进行预览确认。 https://mac.wmzhe.com/article/10085.html
12.PreScan教程:2.道路设置PreScan教程:2.道路设置 道路片段选取 PreScan的场景搭建少不了道路的设置,在 PreScan GUI 的侧边栏 Infrastructure → Road Segment 中,所提供的道路片段可拼装大部分常见道路。 以 Staight Road 为例,直接从左侧拖拽至右侧即可。 车道数量、方向设置 道路默认为两车道,可在右侧 Property Editor 中,修改 Nuhttps://www.pianshen.com/article/71771071549/
13.Revit2017族库样板项目样板离线包安装以及设置教程视频–Nao4、同样方法安装Libraries文件。 5、打开路径: C:ProgramDataAutodeskRVT 2017,就可以看到刚刚安装好的文件。 6、打开Revit软件,依次点击“文件-选项-文件位置” 7、点击”+”,添加各个项目样板,修改对应名称。更改族样板的默认路径为:C:ProgramDataAutodeskRVT 2017Family TemplatesChinese。如果是其他版本,直接修改Revithttp://www.naoket.com/yinan/293.html
14.TeraTerm怎么安装?TeraTerm安装使用详细图文教程编程开发Tera Term是一款串口调试工具,下文小编就为大家带来Tera Term安装使用详细图文教程,需要的朋友可以看看 GPT4.0+Midjourney绘画+国内大模型 会员永久免费使用! 【如果你想靠AI翻身,你先需要一个靠谱的工具!】 Tera Term是来自国外的一款界面简洁,功能实用的串口调试工具。它是Microsoft Windows的终端仿真器,支持串行端口https://www.jb51.net/softjc/619365.html
15.win7家庭版没有个性化设置怎么恢复win7家庭版没有个性化设置恢复win7家庭版没有个性化设置恢复教程 1、在桌面新建一个txt文本文档; 2、把下面代码复制到新建的文本中; [HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionExplorerDesktopNameSpace {031E4825-7B94-4dc3-B131-E946B44C8DD5}] @=“UsersLibraries” https://www.dadighost.com/help/46339.html
16.EndNote设置图文详解与优化基础教程Office办公Libaries指打开EndNote时做什么,是打最近常用的数据库(Open the most recently used library),还是打开特定的数据库(Open the specified libraries,需要设置哪个数据库),还是提示用户打开数据库(Prompt to select a library),或者什么都不做(Do noting)。 https://www.sucai999.com/officebg/110035.html
17.在Python中设置Pandas数据框的背景颜色和字体颜色极客教程# Importing the necessary libraries -->importpandasaspdimportnumpyasnp# Seeding random data from numpynp.random.seed(24)# Making the DataFramedf=pd.DataFrame({'A':np.linspace(1,10,10)})df=pd.concat([df,pd.DataFrame(np.random.randn(10,4),columns=list('BCDE'))],axis=1)# DataFrame whttps://geek-docs.com/pandas/pandas-examples/set-pandas-dataframe-background-color-and-font-color-in-python.html
18.ISE和Modelsim安装破解教程本教程内容: ISE和Modelsim安装及破解教程 ISE 联合 Modelsim 仿真设置 软件版本: Xilinx 官方提供的 ISE14.7 版本 Modelsim_10.1c 软件下载地址: ISE链接:https://pan.baidu.com/s/17z64cN0iSbEKNjAZ_uMqcA 提取码:hqp4 Modelsim链接:https://pan.baidu.com/s/1bpC1lw6rOZ0nZA60JU3PqA 提取码:xmz8 https://m.elecfans.com/article/2194353.html
19.Git教程之设置.gitignore,IDEA安装插件以及设置全局文件Git 教程之 设置 .gitignore, IDEA 安装插件以及设置全局文件 在使用GitHub 或者 GitLab 等分布式代码管理平台时,我们在进行代码提交的时候,往往不需要把所有的东西,比如一些无用的文件或者隐私的文件不需要进行上传,那个Git 提供 .gitignore 文件用来忽略不想要上传的问题。 https://www.jianshu.com/p/2522d711b323
20.新提醒Engine2.1采样器图文安装入库教程WIN简单设置以及入库教程 安装完毕之后,运行桌面上的Engine 2图标。首次运行会提示我们进行声卡和输入设备的设置。 大家根据自己的声卡进行选择、我用的是Yamaha的UR22 mk2。选择好点击OK。 MIDI键盘也就是输入设备In我用的是KeyLab 88。 然后Out输出我们要选择我们的声卡。选择好点击OK。 http://www.360doc.com/content/20/1002/14/11593497_938538450.shtml
21.Axure画原型图的入门教程在打开画布后,首先可以根据设计的目标设备来设置页面尺寸,Axure 画原型图提供了许多不同的设备尺寸,在“ Style ” 中就能搜索自己需要的原型尺寸并应用。 3、使用部件库 在选择完原型尺寸之后,就可以使用 Axure 画原型图的部件库来开始自己接下来的设计。Axure 画原型图的部件库在 “ Libraries ” 窗格中,只需要https://js.design/special/article/axure-painting-prototype-tutorial.html
22.CircuitCAM中文教程下面是一个DC启动文件的实例,它包含了几乎所有重要的设置,下文将结合该实例解释启动文件中各项设置的具体含义。 例1-1(一个DC启动文件): search_path= search_path + {“.”, synopsys_root + “/dw/sim_ver” } search_path= search_path + { “~/risc32/synthesis/libraries” } target_library={ https://m.360docs.net/doc/info-edd68b0feff9aef8941e06ef.html
23.电路设计软件系列教程(一),ProtelDXP电路设计软件之基础操作在你开始绘制电路图之前首先要做的是设置正确的文件夹选项。完成以下步骤: 1、从菜单选择 Design > Options , 文件夹选项对话框打开。作为本教程,在此我们唯一需要修改的是将图纸大小( sheet size ) 设置为标准A4格式。在 Sheet Options 标签,找到 Standard Styles 栏。点击输入框旁的箭头将看见一个图纸样式的列表http://www.chinaaet.com/article/3000111893