2011-08-28 85 views
7

我一直在學習遊戲開發的一些lua。我聽說過其他語言的協程,但在lua中真的出現了。我真的不明白它們的用處是多麼的有用,我聽到很多人都在談論它是如何做一個多線程的東西的方法,但是它們不是按順序運行的嗎?那麼正常的函數也會有什麼好處呢?我只是沒有看到它們與功能的區別,只不過它們可以暫停而讓另一次運行。似乎用例場景對我來說不會那麼重要。協程有什麼好處?

任何人都在關注爲什麼有人會從中受益?

特別是從一個遊戲編程的角度洞察將是很好的^^

+0

他們的歷史可以追溯到上個世紀。多核cpus和從cpu緩存中取消的懲罰性延遲放到了他們的用處。線程是它。 –

+2

@Hans Passant:這完全忽略了協程的點。協程並不是線程的替代品,您不會將它們用於您將使用線程的同一件事。關鍵是寫一個乾淨而舒適的(非併發!)代碼,其中可以暫停一個函數調用,以便在有更多信息時可以返回,而不會阻塞主循環。這樣做沒有任何開銷,這是lua做的。在那個用例中,操作系統線程將是一個糟糕的替代品。 –

回答

0

我們使用他們的一個項目我的工作。對我們來說主要的好處是,有時候使用異步代碼,有些地方很重要,因爲某些依賴關係,某些部分依次運行。如果使用協同程序,則可以強制一個進程等待另一個進程完成。他們不是唯一的方式來做到這一點,但他們可以比其他方法簡單得多。

0

我只是沒有得到多麼不同,他們從功能,但 他們可以暫停,讓另一個運行一秒。

這是一個非常重要的屬性。我曾在一個遊戲引擎上使用它們進行計時。例如,我們有一個每秒鐘運行10次的引擎,並且您可以WaitTicks(x)等待x個tick,並且在用戶層中,您可以運行WaitFrame(x)來等待x個幀。

即使專業的本地併發庫也使用相同的產生行爲。

16

好吧,從遊戲開發的角度思考。

假設你正在做一個過場動畫或者一個教程。無論哪種方式,你有什麼是一個有序的命令序列發送到一些實體。一個實體移動到一個位置,與一個男人談話,然後走到其他地方。等等。一些命令在其他人完成之後才能啓動。

現在回頭看看你的遊戲是如何工作的。每一幀都必須處理AI,碰撞測試,動畫,渲染和聲音等等。你只能思考每一幀。那麼你怎麼把這種代碼放進去,在做下一個代碼之前你必須等待一些行動才能完成?

如果你用C++構建了一個系統,你會得到什麼是在AI之前運行的。它會有一系列要處理的命令。其中一些命令可能是瞬時的,比如「告訴實體X去這裏」或「在這裏產生實體Y」。其他人不得不等待,比如「告訴實體Z去這裏,不要再處理命令,直到它到達這裏」。命令處理器必須在每一幀被調用,並且它必須理解諸如「實體在位置」等複雜條件。

在Lua中,它應該是這樣的:

local entityX = game:GetEntity("entityX"); 
entityX:GoToLocation(locX); 
local entityY = game:SpawnEntity("entityY", locY); 
local entityZ = game:GetEntity("entityZ"); 
entityZ:GoToLocation(locZ); 
do 
    coroutine.yield(); 
until (entityZ:isAtLocation(locZ)); 
return; 

在C++的大小,你會直到它完成一次恢復每幀的這個腳本。一旦它返回,你就知道這個過場動畫已經結束了,所以你可以把控制權交還給用戶。

看看Lua邏輯有多簡單。它的確如它所說的那樣。很明顯,很明顯,因此很難弄錯。

協程的能力在於能夠部分地完成某項任務,等待條件成真,然後繼續下一個任務。

+0

因此,例如我可以有一個加載函數來初始化一些變量並說出一些加載屏幕細節,然後將控制權交給繪製函數,並將控制權交還給加載函數以完成加載我遊戲的所有內容? – Isaiah

+0

@Isaiah:是的,你可以這樣做。 –

+2

如果你想要這個模式的「真實生活」例子,請看這裏:http://getmoai.com/moai-platform-tutorials/moai-tutorials-bug-squisher.html – catwell

0

很多遊戲開發者的好例子。我會在應用程序擴展空間中給予另一個。考慮應用程序有一個引擎可以在Lua中運行用戶例程的情況,同時在C中執行核心功能。如果用戶需要等待引擎達到特定狀態(例如等待數據被接收),你要麼必須:

  • 多線程的C程序在一個單獨的線程中運行的Lua,並添加鎖定和同步方法,
  • 異常終止的Lua程序並用狀態傳遞給從一開始就重試函數跳過任何東西,最少重新運行一些應該只運行一次的代碼,或者
  • 產生Lua例程,並在達到狀態後恢復它C

第三個選項對我來說是最容易實現的,避免了在多個平臺上處理多線程的需要。它還允許用戶的代碼不加修改地運行,看起來好像他們調用的函數花了很長時間。

1

在遊戲中的協同工作: 易於使用,在許多地方使用時很容易搞砸。

只要小心,不要在很多地方使用它。 不要讓您的整個AI代碼依賴於協程。

協調器在引入之前不存在的狀態時可以快速修復。

這正是java所做的。睡眠()和等待() 這兩種功能都是讓您無法調試遊戲的最佳方式。 如果我是你,我會完全避免使用像Coroutine那樣的Wait()函數的任何代碼。

OpenGL API是你應該注意的事情。它從不使用wait()函數,而是使用乾淨的狀態機,該狀態機確切知道對象所處的狀態。 如果你使用協程,那麼你最終會得到很多無狀態的代碼,它肯定會壓倒性地進行調試。

當你正在製作像文本編輯器..銀行應用程序..服務器..數據庫等(不是遊戲)的應用程序時,協程是很好的。 當你在任何時候發生任何事情的遊戲時都很糟糕,你需要有狀態。

所以,在我看來,協程是一種不好的編程方式,也是編寫小型無狀態代碼的藉口。

但這就是我。