Pergunta

Eu tenho algum código de transferência de arquivos de alto desempenho que escrevi em C# usando o Modelo de Programação Async (APM) Idiom (por exemplo, BeginRead/EndRead). Este código lê um arquivo de um disco local e o grava em um soquete.

Para melhor desempenho no hardware moderno, é importante manter mais de uma excelente operação de E/S em voo sempre que possível. Assim, eu posto vários BeginRead operações no arquivo, então quando se conclui, eu chamo um BeginSend no soquete, e quando isso concluir eu faço outro BeginRead no arquivo. Os detalhes são um pouco mais complicados do que isso, mas no alto nível é a ideia.

Eu tenho o código baseado em APM funcionando, mas é muito difícil de seguir e provavelmente tem bugs de simultaneidade sutis. Eu adoraria usar o TPL para isso. imaginei Task.Factory.FromAsync Seria quase fazer isso, mas há um problema.

Todas as amostras de E/S que eu já vi (mais particularmente o StreamExtensions classe nas extensões paralelas extras) Suponha uma leitura seguida de uma gravação. Isso não será executado da maneira que eu preciso.

Eu não posso usar algo simples como Parallel.ForEach ou a extensão dos extras Task.Factory.Iterate Como as tarefas de E/S assínconais não gastam muito tempo em um tópico de trabalhador, então o paralelo inicia outra tarefa, resultando em potencialmente dezenas ou centenas de operações de E/S pendentes; Demais! Você pode contornar isso por Waitem suas tarefas, mas isso causa a criação de um identificador de evento (um objeto de kernel) e uma espera bloqueadora em uma alça de espera, que amarra um fio de trabalhador. Minha implementação baseada em APM evita essas duas coisas.

Eu tenho brincado com maneiras diferentes de manter várias operações de leitura/gravação em voo, e consegui fazer isso usando continuações que chamam um método que cria outra tarefa, mas parece estranho e definitivamente não parece TPL idiomático.

Alguém mais enfrentou um problema como esse com o TPL? Alguma sugestão?

Foi útil?

Solução

Se você está preocupado com muitos tópicos, você pode simplesmente definir ParallelOptions.MaxDegreeOfParallelism para um número aceitável em sua chamada para Parallel.ForEach.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top