自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

使用Python和Asyncio編寫在線多人游戲(一)

開發(fā) 前端
你在 Python 中用過異步編程嗎?本文中我會告訴你怎樣做,而且用一個能工作的例子來展示它:這是一個流行的貪吃蛇游戲,而且是為多人游戲而設計的。

[[171569]]

你在 Python 中用過異步編程嗎?本文中我會告訴你怎樣做,而且用一個能工作的例子來展示它:這是一個流行的貪吃蛇游戲,而且是為多人游戲而設計的。

1、簡介

在技術和文化領域,大規(guī)模多人在線游戲(MMO)毋庸置疑是我們當今世界的潮流之一。很長時間以來,為一個 MMO 游戲?qū)懸粋€服務器這件事總是會涉及到大量的預算與復雜的底層編程技術,不過在最近這幾年,事情迅速發(fā)生了變化?;趧討B(tài)語言的現(xiàn)代框架允許在中檔的硬件上面處理大量并發(fā)的用戶連接。同時,HTML5 和 WebSockets 標準使得創(chuàng)建基于實時圖形的游戲的直接運行至瀏覽器上的客戶端成為可能,而不需要任何的擴展。

對于創(chuàng)建可擴展的非堵塞性的服務器來說,Python 可能不是***的工具,尤其是和在這個領域里***的 Node.js 相比而言。但是最近版本的 Python 正在改變這種現(xiàn)狀。asyncio 的引入和一個特別的 async/await 語法使得異步代碼看起來像常規(guī)的阻塞代碼一樣,這使得 Python 成為了一個值得信賴的異步編程語言,所以我將嘗試利用這些新特點來創(chuàng)建一個多人在線游戲。

2、異步

一個游戲服務器應該可以接受盡可能多的用戶并發(fā)連接,并實時處理這些連接。一個典型的解決方案是創(chuàng)建線程,然而在這種情況下并不能解決這個問題。運行上千的線程需要 CPU 在它們之間不停的切換(這叫做上下文切換),這將導致開銷非常大,效率很低下。更糟糕的是使用進程來實現(xiàn),因為,不但如此,它們還會占用大量的內(nèi)存。在 Python 中,甚至還有一個問題,Python 的解釋器(CPython)并不是針對多線程設計的,相反它主要針對于單線程應用實現(xiàn)***的性能。這就是為什么它使用 GIL(global interpreter lock),這是一個不允許同時運行多線程 Python 代碼的架構(gòu),以防止同一個共享對象出現(xiàn)使用不可控。正常情況下,在當前線程正在等待的時候,解釋器會轉(zhuǎn)換到另一個線程,通常是等待一個 I/O 的響應(舉例說,比如等待 Web 服務器的響應)。這就允許在你的應用中實現(xiàn)非阻塞 I/O 操作,因為每一個操作僅僅阻塞一個線程而不是阻塞整個服務器。然而,這也使得通常的多線程方案變得幾近無用,因為它不允許你并發(fā)執(zhí)行 Python 代碼,即使是在多核心的 CPU 上也是這樣。而與此同時,在一個單一線程中擁有非阻塞 I/O 是完全有可能的,因而消除了經(jīng)常切換上下文的需要。

實際上,你可以用純 Python 代碼來實現(xiàn)一個單線程的非阻塞 I/O。你所需要的只是標準的 select 模塊,這個模塊可以讓你寫一個事件循環(huán)來等待未阻塞的 socket 的 I/O。然而,這個方法需要你在一個地方定義所有 app 的邏輯,用不了多久,你的 app 就會變成非常復雜的狀態(tài)機。有一些框架可以簡化這個任務,比較流行的是 tornade 和 twisted。它們被用來使用回調(diào)方法實現(xiàn)復雜的協(xié)議(這和 Node.js 比較相似)。這種框架運行在它自己的事件循環(huán)中,按照定義的事件調(diào)用你的回調(diào)函數(shù)。并且,這或許是一些情況的解決方案,但是它仍然需要使用回調(diào)的方式編程,這使你的代碼變得碎片化。與寫同步代碼并且并發(fā)地執(zhí)行多個副本相比,這就像我們在普通的線程上做的一樣。在單個線程上這為什么是不可能的呢?

這就是為什么出現(xiàn)微線程(microthread)概念的原因。這個想法是為了在一個線程上并發(fā)執(zhí)行任務。當你在一個任務中調(diào)用阻塞的方法時,有一個叫做“manager” (或者“scheduler”)的東西在執(zhí)行事件循環(huán)。當有一些事件準備處理的時候,一個 manager 會轉(zhuǎn)移執(zhí)行權給一個任務,并等著它執(zhí)行完畢。任務將一直執(zhí)行,直到它遇到一個阻塞調(diào)用,然后它就會將執(zhí)行權返還給 manager。

微線程也稱為輕量級線程(lightweight threads)或綠色線程(green threads)(來自于 Java 中的一個術語)。在偽線程中并發(fā)執(zhí)行的任務叫做 tasklets、greenlets 或者協(xié)程(coroutines)。

Python 中的微線程最早的實現(xiàn)之一是 Stackless Python。它之所以這么知名是因為它被用在了一個叫 EVE online 的非常有名的在線游戲中。這個 MMO 游戲自稱說在一個持久的“宇宙”中,有上千個玩家在做不同的活動,這些都是實時發(fā)生的。Stackless 是一個獨立的 Python 解釋器,它代替了標準的函數(shù)棧調(diào)用,并且直接控制程序運行流程來減少上下文切換的開銷。盡管這非常有效,這個解決方案不如在標準解釋器中使用“軟”庫更流行,像 eventlet 和 gevent 的軟件包配備了修補過的標準 I/O 庫,I/O 函數(shù)會將執(zhí)行權傳遞到內(nèi)部事件循環(huán)。這使得將正常的阻塞代碼轉(zhuǎn)變成非阻塞的代碼變得簡單。這種方法的一個缺點是從代碼上看這并不分明,它的調(diào)用是非阻塞的。新版本的 Python 引入了本地協(xié)程作為生成器的高級形式。在 Python 的 3.4 版本之后,引入了 asyncio 庫,這個庫依賴于本地協(xié)程來提供單線程并發(fā)。但是僅僅到了 Python 3.5 ,協(xié)程就變成了 Python 語言的一部分,使用新的關鍵字 async 和 await 來描述。這是一個簡單的例子,演示了使用 asyncio 來運行并發(fā)任務。

  1. import asyncio 
  2. async def my_task(seconds): 
  3.     print("start sleeping for {} seconds".format(seconds)) 
  4.     await asyncio.sleep(seconds) 
  5.     print("end sleeping for {} seconds".format(seconds)) 
  6. all_tasks = asyncio.gather(my_task(1), my_task(2)) 
  7. loop = asyncio.get_event_loop() 
  8. loop.run_until_complete(all_tasks) 
  9. loop.close()     

我們啟動了兩個任務,一個睡眠 1 秒鐘,另一個睡眠 2 秒鐘,輸出如下:

  1. start sleeping for 1 seconds 
  2. start sleeping for 2 seconds 
  3. end sleeping for 1 seconds 
  4. end sleeping for 2 seconds 

正如你所看到的,協(xié)程不會阻塞彼此——第二個任務在***個結(jié)束之前啟動。這發(fā)生的原因是 asyncio.sleep 是協(xié)程,它會返回執(zhí)行權給調(diào)度器,直到時間到了。

在下一節(jié)中,我們將會使用基于協(xié)程的任務來創(chuàng)建一個游戲循環(huán)。

責任編輯:龐桂玉 來源: Linux中國
相關推薦

2016-09-22 21:12:14

2016-09-19 21:24:08

PythonAsyncio游戲

2010-03-05 18:42:31

杜比語音聊天

2020-02-21 08:00:00

Pythonasyncio編程語言

2021-04-13 06:35:13

Elixir語言編程語言軟件開發(fā)

2018-06-27 14:50:06

Cloud StudiSpring Boot應用

2021-01-01 19:30:21

Python編程語言

2011-12-16 10:08:36

Node.js

2021-09-15 14:53:35

在線文檔多人協(xié)作

2024-01-18 08:37:33

socketasyncio線程

2015-07-31 10:10:12

javaweb在線聊天

2014-11-20 13:56:08

2021-09-08 15:43:03

在線寫作協(xié)作文檔辦公軟件

2020-01-16 11:42:45

PyramidCornicePython Web

2018-10-08 15:35:56

Python異步IO

2020-09-21 08:58:57

PythonOpenCV乒乓球

2023-08-30 08:43:42

asyncioaiohttp

2017-05-05 08:44:24

PythonAsyncio異步編程

2017-09-05 08:08:37

asyncio程序多線程

2014-10-30 10:28:55

Node.js
點贊
收藏

51CTO技術棧公眾號