English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Lua coroutine (coroutine) is similar to threads: it has an independent stack, independent local variables, and an independent instruction pointer, while also sharing global variables and most other things with other coroutines.
Cooperation is a very powerful feature, but it is also very complex to use.
A principal diferença entre thread e coroutine está no fato de que um programa com múltiplas threads pode executar várias threads ao mesmo tempo, enquanto as coroutines precisam funcionar em colaboração.
Apenas uma coroutine pode estar em execução em qualquer momento designado, e a coroutine em execução só pode ser suspensa explicitamente
As coroutines são um pouco semelhantes a threads sincronizadas, várias threads esperando o mesmo bloqueio de thread são um pouco semelhantes a coroutines.
Método | Descrição |
---|---|
coroutine.create() | Cria uma coroutine, retorna a coroutine, o parâmetro é uma função, quando usado com resume, acorda a chamada da função |
coroutine.resume() | Reiniciar a coroutine, usado com create |
coroutine.yield() | Suspender a coroutine, configurar a coroutine para o estado suspenso, isso pode ser usado com resume para obter muitos efeitos úteis |
coroutine.status() | Verificar o estado da coroutine Nota: o estado da coroutine tem três: morto, suspenso, em execução, quando tem esses estados, consulte o programa abaixo |
coroutine.wrap() | Cria uma coroutine, retorna uma função, uma vez que você chama essa função, entra na coroutine, tem a mesma função que create |
coroutine.running() | Retorna a coroutine em execução, uma coroutine é uma thread, quando usar running, retorna o número da thread da coroutine |
-- arquivo coroutine_test.lua co = coroutine.create( função(i) print(i); end ) coroutine.resume(co, 1) -- 1 print(coroutine.status(co)) -- morto print("----------") co = coroutine.wrap( função(i) print(i); end ) co(1) print("----------") co2 = coroutine.create( função() para i=1,10 faça print(i) se i == 3 então print(coroutine.status(co)2)) --em execução print(coroutine.running()) --thread:XXXXXX end coroutine.yield() end end ) coroutine.resume(co2) --1 coroutine.resume(co2) --2 coroutine.resume(co2) --3 print(coroutine.status(co)2)) -- suspended print(coroutine.running()) print("----------")
O resultado de execução dos exemplos acima é:
1 morto ---------- 1 ---------- 1 2 3 em execução thread: 0x7fb801c05868 falso suspended thread: 0x7fb801c04c88 true ----------
coroutine.running can be seen, coroutine is implemented as a thread in the underlying implementation.
When creating a coroutine, it is like registering an event in a new thread.
When using resume to trigger an event, the coroutine function of create is executed. When encountering yield, it means suspending the current thread and waiting for the next resume to trigger the event.
Next, we analyze a more detailed example:
function foo (a) print("foo function output", a) return coroutine.yield(2 * a) -- return 2*a's value end co = coroutine.create(function (a , b) print("the first coroutine execution output", a, b) -- co-body 1 10 local r = foo(a + 1) print("the second coroutine execution output", r) local r, s = coroutine.yield(a + b, a - b) -- a, b's value is the value passed when the coroutine is called for the first time print("the third coroutine execution output", r, s) return b, "end coroutine" -- b's value is the value passed when the coroutine is called for the second time end) print("main", coroutine.resume(co, 1, 10)) -- true, 4 print("--division line----") print("main", coroutine.resume(co, "r")) -- true 11 -9 print("---division line---") print("main", coroutine.resume(co, "x", "y")) -- true 10 end print("---division line---") print("main", coroutine.resume(co, "x", "y")) -- cannot resume dead coroutine print("---division line---")
O resultado de execução dos exemplos acima é:
the first coroutine execution output 1 10 foo function output 2 main true 4 --division line---- the second coroutine execution output r main true 11 -9 ---division line--- the third coroutine execution output x y main true 10 end coroutine ---division line--- main false cannot resume dead coroutine ---division line---
the following example continues as follows:
call resume to wake up the coroutine, resume operation returns true if successful, otherwise returns false;
coroutine runs;
run to the yield statement;
yield suspend a coroutine, the first resume returns; (note: here yield returns, the parameter is resume's parameter)
Segunda chamada de resume, acordando novamente a coroutine; (Atenção: os parâmetros restantes do resume, além do primeiro, são os parâmetros do yield)
yield retorna;
A coroutine continua a executar;
Se o coroutine continuar a ser chamado após o término da execução, será exibido: cannot resume dead coroutine
A força da combinação de resume e yield está na capacidade de resume estar no contexto principal, inserindo o estado externo (dados) dentro da coroutine; enquanto yield retorna o estado interno (dados) para o contexto principal.
Agora, eu vou usar coroutines do Lua para resolver o problema de produtor-Este é um problema clássico de consumidor.
local newProductor function productor() local i = 0 while true do i = i + 1 send(i) -- Enviar item produzido ao consumidor end end function consumer() while true do local i = receive() -- Obter item do produtor print(i) end end function receive() local status, value = coroutine.resume(newProductor) return value end function send(x) coroutine.yield(x) -- x representa o valor a ser enviado, após o valor ser retornado, a coroutine é pausada end -- Iniciar programa newProductor = coroutine.create(productor) consumer()
O resultado de execução dos exemplos acima é:
1 2 3 4 5 6 7 8 9 10 11 12 13 ……