Coroutines são basicamente funções cuja execução pode ser pausada/suspensa em um determinado ponto e, em seguida, podemos retomar a execução a partir desse mesmo ponto mais tarde, sempre que quisermos.

precisamos de um mecanismo – ou para ser mais preciso, uma palavra — chave-pelo qual podemos inserir um ponto de verificação e dizer ao programa que queremos pausar a execução da função aqui e retornar o controle ao ponto de onde ele chamou. Vamos retomar a execução sempre que quisermos.

em Python, podemos pausar a execução de uma função usando a palavra-chave yield.

então aqui é onde as coisas ficam interessantes:

  • podemos pensar em uma coroutine como uma função que tem um ou mais pontos de verificação onde a execução será pausada e o controle será retornado ao ponto de onde foi chamado.
  • Em essência, uma co-rotina é uma função dividido em muitas partes, e podemos executar cada parte de uma co-rotina como nós execução de cada iteração de um loop usando o next função.

aqui está um exemplo básico:

OUTPUT :<class 'generator'>
Function Starts
Function Ends

a partir da saída, notamos algumas coisas:

  • primeiro, precisamos chamar a coroutina / função que nos dará um objeto gerador.
  • esse objeto gerador se comportará de forma semelhante a um iterador, mas no caso de um iterador, estamos atravessando um iterável. Com um gerador, estamos executando partes da coroutina.
  • como a StopIteration exceção é lançada e pego os bastidores de um loop for, o mesmo acontece neste caso quando a última parte da co-rotina é executada.

agora esta pausa da função no meio é muito interessante e abre algumas possibilidades:

  • quando a função é pausada, não fazemos nada, o que é o caso que acabamos de ver.Suponha que uma variável esteja sendo modificada várias vezes em uma função e queremos o valor dessa variável específica em um determinado ponto de verificação. Então, quando pausamos essa função nesse ponto de verificação específico, ela retorna o valor dessa variável.

Vamos ver um exemplo:

OUTPUT :Function Part 1
5
Function part 2
12
Function part 3

Aqui, o valor de x é retornado por yield em diferentes pontos de verificação, como a função de execução foi interrompida.

sempre que estivermos executando a última parte da função e não houver rendimento na função, Após executar essa última parte, uma exceção StopIteration será levantada.

muito parecido com quando um iterador tenta executar a próxima função, mas não há mais elementos restantes no iterável, ele também levanta a exceção StopIteration.

  • Suponha que queremos enviar um valor (que pode ser uma constante ou variável) em um determinado ponto de verificação (por exemplo, em um determinado estado de uma função). Também podemos fazer isso usando a palavra-chave yield. Quando quisermos enviar um valor, usaremos a função send em vez de next.

Vamos ver um exemplo:

OUTPUT :Function part 1
6
Function part 2
12
Function part 3

O motivo de termos usados next antes de usar send é só podemos usar send quando estamos no yield ponto de verificação, e yield do lado direito da expressão. Então, para alcançar esse primeiro yield, temos que usar a função next.

agora aqui vem uma aplicação interessante de coroutines. Suponha que queremos alternar entre duas funções, como fazemos no multithreading. Em multithreading, até que um interrupt seja encontrado pelo sistema operacional, ele continuará executando. Nesse caso, podemos mudar sempre que quisermos.

Vamos ver um exemplo:

OUTPUT :Function 1 part 1
Function 2 part 1
Function 1 part 2
Function 1 part 3
Function 2 part 2
Function 2 part 3
Function 2 part 4
Function 1 part 4
Function 1 part 5

neste exemplo, podemos ver que podemos alternar entre as co-rotinas, sempre que queremos.

então, se escrevermos nosso próprio Agendador personalizado que lida com a troca entre várias coroutinas, podemos conseguir com um único threading o que fazemos com multithreading.

as rotinas têm muitas aplicações, como simultaneidade e outros padrões de programação também podem ser implementados, como produtor-consumidor ou remetente-receptor na programação de rede. Vou explorar isso nos próximos artigos.

Coroutines também são os blocos de construção de muitas estruturas, como asyncio, twisted, aiohttp. Eles também podem ser encadeados para fazer pipelines e resolver problemas.