2011-08-28 12 views
7

Uczę się trochę lua do tworzenia gier. Słyszałem o coroutines w innych językach, ale naprawdę wymyśliłem je w lua. Po prostu nie rozumiem, jak bardzo są użyteczne, słyszałem wiele mów, jak to może być sposobem na wielowątkowe rzeczy, ale czy nie są one uruchamiane w kolejności? Jakie są więc korzyści z normalnych funkcji, które działają również w kolejności? Po prostu nie rozumiem, jak bardzo różnią się one od funkcji, z tym wyjątkiem, że mogą zatrzymać się i pozwolić, by inny biegał przez sekundę. Wygląda na to, że scenariusze użycia nie byłyby dla mnie zbyt duże.Jakie są zalety coroutines?

Czy ktoś chce rzucić trochę światła na to, dlaczego ktoś może z nich skorzystać?

Zwłaszcza wgląd z gier programowania perspektywy byłoby miło ^^

+0

Pochodzą z poprzedniego wieku. Wielordzeniowe cpus i kary za opóźnienia związane z odkładaniem pamięci podręcznej cpu są i kończą się ich użytecznością. Nici to jest. –

+2

@Hans Passant: To całkowicie pomija punkt coroutines. Coroutines nie zastępują wątków i nie używasz ich do tego samego, do którego używasz wątków. Chodzi o to, aby napisać czysty i wygodny (niezwiązany z prądem!) Kod, w którym wywołanie funkcji może zostać wstrzymane, aby można było powrócić, gdy masz więcej informacji, bez blokowania głównej pętli. Nie ma na to żadnego wpływu, podobnie jak robi to lua. Gwinty systemu operacyjnego byłyby słabym substytutem w tym przypadku użycia. –

Odpowiedz

0

Używamy ich w projekcie pracuję nad. Główną korzyścią dla nas jest to, że czasami z kodem asynchronicznym, istnieją punkty, w których ważne jest, aby niektóre części były uruchamiane w porządku z powodu pewnych zależności. Jeśli używasz coroutines, możesz zmusić jeden proces do oczekiwania na zakończenie innego procesu. Nie są to jedyne sposoby, aby to zrobić, ale mogą być znacznie prostsze niż inne metody.

0

Po prostu nie rozumiem, jak różne są one od funkcji, z wyjątkiem tego, że mogą się zatrzymać i pozwolić, aby inny działał przez sekundę.

To bardzo ważna właściwość. Pracowałem na silniku gry, który wykorzystywał je do synchronizacji. Na przykład, mieliśmy silnik, który działał z szybkością 10 cykli na sekundę, a Ty mogłeś czekać na x liczbę znaczników, a w warstwie użytkownika mogłeś uruchomić WaitFrames (x), aby czekać x klatek.

Nawet profesjonalne natywne biblioteki współbieżności używają tego samego rodzaju zachowania plonotwórczego.

16

OK, pomyśl o rozwoju gry.

Załóżmy, że robisz cutscenkę lub samouczek. Tak czy inaczej, masz uporządkowaną sekwencję poleceń wysyłanych do pewnej liczby jednostek. Jednostka przesuwa się do miejsca, rozmawia z facetem, a potem idzie gdzie indziej. I tak dalej. Niektóre polecenia nie mogą zostać uruchomione, dopóki inne nie zostaną zakończone.

Zobacz, jak działa Twoja gra. Każda klatka musi przetwarzać sztuczną inteligencję, testy kolizji, animację, rendering i dźwięk, między innymi. Możesz myśleć tylko o każdej klatce. Więc w jaki sposób umieścić ten kod w, gdzie trzeba czekać na zakończenie jakiejś czynności przed wykonaniem następnego?

Jeśli zbudowałeś system w C++, to co masz, to coś, co działało przed AI. Będzie miał sekwencję poleceń do przetworzenia. Niektóre z tych poleceń byłyby natychmiastowe, jak "powiedz jednostce X, aby tu" lub "odradzać istotę Y tutaj". Inni będą musieli poczekać, np. "Powiedz jednostce Z, aby tu przybyła i nie przetwarzaj już poleceń, dopóki nie dotrze tutaj". Procesor poleceń musiałby być wywoływany w każdej klatce i musiałby rozumieć złożone warunki, takie jak "istota jest na miejscu" i tak dalej.

W Lua, to będzie wyglądać następująco:

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; 

W C++ rozmiarze, należy wznowić ten skrypt raz na ramkę, dopóki nie zostanie zrobione. Po powrocie wiesz, że cutscena się skończyła, więc możesz zwrócić kontrolę użytkownikowi.

Zobacz, jak prosta jest logika Lua. Robi dokładnie to, co mówi. Jest to oczywiste, oczywiste i dlatego bardzo trudno jest się pomylić.

Mocą coroutines jest możliwość częściowego wykonania jakiegoś zadania, oczekiwania na spełnienie warunku, a następnie przejścia do następnego zadania.

+0

Więc na przykład mogę mieć funkcję ładowania, która inicjuje niektóre zmienne i podaje niektóre szczegóły ekranu ładowania, a następnie przekazuje kontrolę do funkcji rysowania, która rysuje je i przekazuje kontrolę z powrotem do funkcji ładowania, aby zakończyć ładowanie wszystkiego dla mojej gry? – Isaiah

+0

@Isaiah: Tak, możesz to zrobić. –

+2

Jeśli chcesz zobaczyć przykład tego wzoru z "prawdziwego życia": http://getmoai.com/moai-platform-tutorials/moai-tutorials-bug-squisher.html – catwell

0

Wiele dobrych przykładów dla twórców gier. Daję inny w obszarze rozszerzenia aplikacji. Rozważ scenariusz, w którym aplikacja ma silnik, który może uruchamiać procedury użytkownika w Lua, wykonując podstawową funkcjonalność w C. Jeśli użytkownik musi poczekać, aż silnik przejdzie do określonego stanu (np. Oczekiwanie na dane do odebrania), trzeba albo:

  • wielowątkowego programu C, aby uruchomić Lua w osobnym wątku i dodać blokujących i synchronizacji metod
  • Abend rutyny Lua i ponownie od początku ze stanem przekazywane do funkcja do pominięcia czegokolwiek, przynajmniej ponownie uruchomiłeś kod, który powinien być uruchamiany tylko raz, lub
  • wykonaj procedurę Lua i wznów ją, gdy stan zostanie osiągnięty w C

Trzecia opcja jest najłatwiejsza do implementacji, unikając konieczności obsługi wielowątkowości na wielu platformach. Pozwala także na niezmodyfikowany kod użytkownika, wyglądający tak, jakby wywoływana przez niego funkcja trwała długo.

1

Coroutines w grze: Łatwy w użyciu, Łatwy do zerwania, gdy jest używany w wielu miejscach.

Po prostu bądź ostrożny i nie używaj go w wielu miejscach. Nie uzależniaj całego kodu AI od Coroutines.

Coruleny są dobre do szybkiego rozwiązania, gdy wprowadzono stan, który wcześniej nie istniał.

To jest dokładnie to, co robi java. Tryb uśpienia() i oczekiwanie() Obie funkcje są najlepszymi sposobami uniemożliwienia debugowania gry. Gdybym był tobą, całkowicie uniknąłbym kodu, który musiałby używać funkcji Wait() takiej jak Coroutine.

OpenGL API jest czymś, co należy wziąć pod uwagę. Nigdy nie używa funkcji wait(), ale zamiast tego używa maszyny z czystym stanem, która dokładnie wie, w jakim stanie znajduje się obiekt. Jeśli używasz coroutines, kończysz z wieloma bezpaństwowymi kodami, które z pewnością będą przytłaczające do debugowania.

Coroutsines są dobre podczas tworzenia aplikacji takich jak Text Editor ..bank application .. server ..database itp. (Nie gra). Złe, gdy tworzysz grę, w której wszystko może się zdarzyć w dowolnym momencie, musisz mieć stany.

Tak, moim zdaniem Coroutines są złym sposobem programowania i pretekstem do napisania małego kodu bezstanowego.

Ale to tylko ja.