Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Duas formas de programação em Orleans são relevantes para grãos:
- Agendamento de Solicitação: agendamento de chamadas de entrada de grãos para execução de acordo com as regras discutidas no Agendamento de Solicitação.
- Agendamento de Tarefas: agendando blocos síncronos de código para serem executados de forma monothread.
Todo o código de grão é executado no agendador de tarefas do grão, o que significa que as solicitações também são executadas no agendador de tarefas do grão. Mesmo que as regras de agendamento de solicitação permitam que várias solicitações sejam executadas simultaneamente, elas não serão executadas em paralelo porque o agendador de tarefas do grão sempre executa tarefas uma a uma e nunca executa várias tarefas em paralelo.
Agendamento de tarefas
Para entender melhor o agendamento, considere o seguinte grão. MyGrain Ele tem um método chamado DelayExecution() que registra uma mensagem, aguarda algum tempo e registra outra mensagem antes de retornar.
public interface IMyGrain : IGrain
{
Task DelayExecution();
}
public class MyGrain : Grain, IMyGrain
{
private readonly ILogger<MyGrain> _logger;
public MyGrain(ILogger<MyGrain> logger) => _logger = logger;
public async Task DelayExecution()
{
_logger.LogInformation("Executing first task");
await Task.Delay(1_000);
_logger.LogInformation("Executing second task");
}
}
Quando esse método é executado, o corpo do método é executado em duas partes:
- A primeira
_logger.LogInformation(...)ligação e a ligação paraTask.Delay(1_000). - A segunda
_logger.LogInformation(...)chamada.
A segunda tarefa não é programada no agendador de tarefas do "grain" até que a chamada Task.Delay(1_000) seja concluída. Nesse ponto, ele agenda a continuação do método grain.
Aqui está uma representação gráfica de como uma solicitação é agendada e executada como duas tarefas:
A descrição acima não é específica para Orleans; ela descreve como o agendamento de tarefas funciona no .NET. O compilador C# converte métodos assíncronos em um computador de estado assíncrono e a execução progride por meio desse computador de estado em etapas discretas. Cada etapa agenda no atual TaskScheduler (acessado por meio de TaskScheduler.Current, padrão para TaskScheduler.Default) ou no atual SynchronizationContext. Se um TaskScheduler for usado, cada passo do método representará uma instância de Task passada para aquele TaskScheduler. Portanto, um Task no .NET pode representar duas coisas conceituais:
- Uma operação assíncrona que pode ser esperada. A execução acima do método
DelayExecution()é representada por um Task que pode ser esperado. - Um bloco síncrono de trabalho. Cada estágio dentro do
DelayExecution()método acima é representado por um Task.
Quando TaskScheduler.Default é usado, as continuações são agendadas diretamente no .NET ThreadPool e não são encapsuladas em um objeto Task. O encapsulamento de continuações em Task instâncias ocorre de forma transparente, portanto, os desenvolvedores raramente precisam estar cientes desses detalhes de implementação.
Agendamento de tarefas em Orleans
Cada ativação de grãos tem sua própria TaskScheduler instância responsável por impor o modelo de execução de thread único de grãos. Internamente, isso TaskScheduler é implementado por meio de ActivationTaskScheduler e WorkItemGroup.
WorkItemGroup mantém tarefas enfileiradas em um Queue<T> (onde T é internamente um Task) e implementa IThreadPoolWorkItem. Para executar cada um dos itens atualmente enfileirados Task, WorkItemGroup programa-se no .NET . Quando o .NET ThreadPool invoca o método WorkItemGroup do IThreadPoolWorkItem.Execute(), o WorkItemGroup executa as instâncias Task enfileiradas uma a uma.
Cada grão tem um agendador que é executado agendando-se no .NET ThreadPool:
Cada agendador contém uma fila de tarefas:
O .NET ThreadPool executa cada item de trabalho enfileirado nele. Isso inclui agendadores de grain, assim como outros itens de trabalho, tais como aqueles agendados por meio de Task.Run(...).
Observação
O agendador de um grão só pode ser executado em um thread de cada vez, mas nem sempre é executado no mesmo thread. O .NET ThreadPool é gratuito para usar um thread diferente sempre que o agendador do grão for executado. O agendador do grão garante que ele seja executado apenas em um thread de cada vez, implementando o modelo de execução de thread único de grãos.