Pin
Os blocos e funções async retornam tipos que implementam o trait Future
. O tipo retornado é o resultado de uma transformação do compilador que transforma variáveis locais em dados armazenados dentro da future.
Algumas dessas variáveis podem conter ponteiros para outras variáveis locais. Por causa disso, a future nunca deve ser movida para uma localização de memória diferente, pois isso invalidaria esses ponteiros.
Para evitar mover o tipo de future na memória, ele só pode ser poll por meio de um ponteiro pinned. Pin
é um invólucro em torno de uma referência que proíbe todas as operações que moveriam a instância para a qual aponta para uma localização de memória diferente.
Speaker Notes
This slide should take about 20 minutes.
-
Você pode reconhecer isso como um exemplo do padrão actor. Os actors tipicamente chamam
select!
em um loop. -
Isso serve como uma síntese de algumas das lições anteriores, então leve seu tempo com isso.
-
Adicione ingenuamente um
_ = sleep(Duration::from_millis(100)) => { println!(..) }
aoselect!
. Isso nunca será executado. Por quê? -
Em vez disso, adicione um
timeout_fut
contendo essa future fora doloop
: -
Isso ainda não funciona. Siga os erros do compilador, adicionando
&mut
aotimeout_fut
noselect!
para contornar a movimentação, e então usandoBox::pin
. -
Isso compila, mas uma vez que o timeout expira, ele é
Poll::Ready
em cada iteração (um fused future ajudaria com isso). Atualize para redefinirtimeout_fut
toda vez que expirar:
-
-
O Box aloca na pilha. Em alguns casos,
std::pin::pin!
(apenas recentemente estabilizado, com código mais antigo frequentemente usandotokio::pin!
) também é uma opção, mas é difícil de usar para uma future que é reatribuída. -
Outra alternativa é não usar
pin
de forma alguma, mas iniciar outra tarefa que enviará para um canaloneshot
a cada 100ms. -
Dados que contêm ponteiros para si mesmos são chamados auto-referenciais. Normalmente, o verificador de empréstimos do Rust impediria que dados auto-referenciais fossem movidos, pois as referências não podem sobreviver aos dados aos quais apontam. No entanto, a transformação de código para blocos e funções async não é verificada pelo verificador de empréstimos.
-
Pin
é um invólucro em torno de uma referência. Um objeto não pode ser movido de seu local usando um ponteiro pinned. No entanto, ele ainda pode ser movido por meio de um ponteiro não pinned. -
O método
poll
do traitFuture
usaPin<&mut Self>
em vez de&mut Self
para se referir à instância. É por isso que ele só pode ser chamado em um ponteiro pinned.