Ir para o conteúdo do rodapé
AJUDA DO .NET

Dicionário Concorrente em C# (Como funciona para desenvolvedores)

Ao trabalhar com aplicações multithread em C#, manter a integridade dos dados é crucial, especialmente ao gerar documentos PDF dinamicamente usando uma biblioteca como o IronPDF . A classe ConcurrentDictionary<TKey, TValue> fornece uma coleção thread-safe para gerenciar pares de chave e valor de forma eficiente, mesmo quando várias threads executam operações como inserções, atualizações ou pesquisas simultaneamente.

Neste guia, exploraremos como o ConcurrentDictionary funciona, como ele pode ser integrado ao IronPDF para processamento paralelo de PDFs e o que todo desenvolvedor .NET precisa saber sobre tipo de chave, segurança de threads e problemas comuns, como lidar com uma chave existente ou garantir a consistência dos dados.

O que é um ConcurrentDictionary em C#?

A classe ConcurrentDictionary<TKey, TValue>, parte do namespace System.Collections.Concurrent, é uma coleção genérica projetada para operações de alto desempenho e seguras para threads. Diferentemente de um dicionário comum, ele permite que múltiplas threads acessem e modifiquem a coleção com segurança, sem bloquear toda a estrutura.

Uma nova instância de ConcurrentDictionary<string, string> pode ter esta aparência:

var dictionary = new ConcurrentDictionary<string, string>();
var dictionary = new ConcurrentDictionary<string, string>();
Dim dictionary = New ConcurrentDictionary(Of String, String)()
$vbLabelText   $csharpLabel

Você pode definir seus próprios tipos TKey e TValue com base em seu caso de uso específico, como armazenar em cache os caminhos de arquivos PDF renderizados ou rastrear tarefas simultâneas de geração de PDF.

Por que usar o ConcurrentDictionary com o IronPDF?

Imagine que você está criando um programa que gera faturas personalizadas usando o IronPDF para milhares de usuários. Se cada thread precisar renderizar um documento e armazenar seu resultado, um dicionário comum introduziria condições de corrida ou lançaria exceções se uma chave já existisse.

O uso de ConcurrentDictionary garante:

  • Consistência de dados entre threads
  • Leitura e escrita eficientes
  • Prevenção de erros de código desconhecidos
  • Sobrecarga de bloqueio zero quando várias threads operam em chaves diferentes.

Métodos comuns e sua utilização com o IronPDF

Vamos analisar os principais métodos usando cenários de renderização do IronPDF .

Método GetOrAdd: Recuperar ou adicionar uma nova chave

Este método verifica se uma chave especificada existe. Caso contrário, adiciona o novo valor.

var filePath = pdfCache.GetOrAdd(userId, id => GeneratePdfForUser(id));
var filePath = pdfCache.GetOrAdd(userId, id => GeneratePdfForUser(id));
Dim filePath = pdfCache.GetOrAdd(userId, Function(id) GeneratePdfForUser(id))
$vbLabelText   $csharpLabel
  • Garante a segurança de threads
  • Evita renderização duplicada
  • Retorna o valor associado à chave fornecida.

Método AddOrUpdate: Lidar com um valor existente de forma adequada

Este método permite atualizar o valor se a chave já existir ou adicionar um novo par chave-valor.

pdfCache.AddOrUpdate(userId,
    id => GeneratePdfForUser(id),
    (id, existingValue) => UpdatePdfForUser(id, existingValue));
pdfCache.AddOrUpdate(userId,
    id => GeneratePdfForUser(id),
    (id, existingValue) => UpdatePdfForUser(id, existingValue));
pdfCache.AddOrUpdate(userId, Function(id) GeneratePdfForUser(id), Function(id, existingValue) UpdatePdfForUser(id, existingValue))
$vbLabelText   $csharpLabel
  • Gerencia a lógica para chaves existentes
  • Garante a segurança dos membros acessados ​​em situações de acesso simultâneo.

Método TryAdd: Adicionar se a chave não existir

Este método tenta adicionar um valor e retorna um valor booleano indicando sucesso.

bool added = pdfCache.TryAdd(userId, pdfBytes);
if (!added)
{
    Console.WriteLine("PDF already cached.");
}
bool added = pdfCache.TryAdd(userId, pdfBytes);
if (!added)
{
    Console.WriteLine("PDF already cached.");
}
Dim added As Boolean = pdfCache.TryAdd(userId, pdfBytes)
If Not added Then
	Console.WriteLine("PDF already cached.")
End If
$vbLabelText   $csharpLabel
  • Ideal para evitar conflitos
  • O método retorna verdadeiro se a inserção for bem-sucedida.

Tabela de casos de uso: Métodos do ConcurrentDictionary

Dicionário Concorrente C# (Como funciona para desenvolvedores): Figura 1 - Tabela de casos de uso

Otimizando para o desempenho

O ConcurrentDictionary suporta ajustes através do construtor:

int concurrencyLevel = 4;
int initialCapacity = 100;
var dictionary = new ConcurrentDictionary<string, byte[]>(concurrencyLevel, initialCapacity);
int concurrencyLevel = 4;
int initialCapacity = 100;
var dictionary = new ConcurrentDictionary<string, byte[]>(concurrencyLevel, initialCapacity);
Dim concurrencyLevel As Integer = 4
Dim initialCapacity As Integer = 100
Dim dictionary = New ConcurrentDictionary(Of String, Byte())(concurrencyLevel, initialCapacity)
$vbLabelText   $csharpLabel
  • concurrencyLevel: Número esperado de threads (padrão = nível de concorrência padrão)
  • initialCapacity: Número esperado de elementos (capacidade inicial padrão)

Configurar esses parâmetros corretamente melhora o desempenho e reduz a disputa entre várias threads.

Prevenindo problemas com conflitos de chaves e valores padrão

Quando uma chave não existe, operações como TryGetValue podem retornar o valor padrão para o tipo:

if (!pdfCache.TryGetValue(userId, out var pdf))
{
    pdf = GeneratePdfForUser(userId); // Second call
}
if (!pdfCache.TryGetValue(userId, out var pdf))
{
    pdf = GeneratePdfForUser(userId); // Second call
}
Dim pdf As var
If Not pdfCache.TryGetValue(userId, pdf) Then
	pdf = GeneratePdfForUser(userId) ' Second call
End If
$vbLabelText   $csharpLabel

Isso protege seu código contra código desconhecido ou referências nulas. Sempre verifique um valor específico antes de presumir a presença de algo.

Exemplo prático: Gerador de relatórios IronPDF seguro para threads

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using IronPdf;
public class Program
{
    static ConcurrentDictionary<string, byte[]> pdfReports =
        new ConcurrentDictionary<string, byte[]>();
    static void Main(string[] args)
    {
        // Simulated user list with HTML content
        var users = new List<User>
        {
            new User { Id = "user1", HtmlContent = "<h1>Report for User 1</h1>" },
            new User { Id = "user2", HtmlContent = "<h1>Report for User 2</h1>" },
            new User { Id = "user3", HtmlContent = "<h1>Report for User 3</h1>" }
        };
        // Generate PDFs concurrently
        var renderer = new ChromePdfRenderer();
        Parallel.ForEach(users, user =>
        {
            var pdf = pdfReports.GetOrAdd(user.Id, id =>
            {
                var pdfDoc = renderer.RenderHtmlAsPdf(user.HtmlContent);
                return pdfDoc.BinaryData;
            });
            SaveToFile(pdf, $"{user.Id}.pdf");
        });
        Console.WriteLine("PDF generation complete.");
    }
    // Utility method to write PDF binary data to file
    static void SaveToFile(byte[] pdfBytes, string filePath)
    {
        File.WriteAllBytes(filePath, pdfBytes);
        Console.WriteLine($"Saved: {filePath}");
    }
}
// Simple user class with ID and HTML content
public class User
{
    public string Id { get; set; }
    public string HtmlContent { get; set; }
}
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using IronPdf;
public class Program
{
    static ConcurrentDictionary<string, byte[]> pdfReports =
        new ConcurrentDictionary<string, byte[]>();
    static void Main(string[] args)
    {
        // Simulated user list with HTML content
        var users = new List<User>
        {
            new User { Id = "user1", HtmlContent = "<h1>Report for User 1</h1>" },
            new User { Id = "user2", HtmlContent = "<h1>Report for User 2</h1>" },
            new User { Id = "user3", HtmlContent = "<h1>Report for User 3</h1>" }
        };
        // Generate PDFs concurrently
        var renderer = new ChromePdfRenderer();
        Parallel.ForEach(users, user =>
        {
            var pdf = pdfReports.GetOrAdd(user.Id, id =>
            {
                var pdfDoc = renderer.RenderHtmlAsPdf(user.HtmlContent);
                return pdfDoc.BinaryData;
            });
            SaveToFile(pdf, $"{user.Id}.pdf");
        });
        Console.WriteLine("PDF generation complete.");
    }
    // Utility method to write PDF binary data to file
    static void SaveToFile(byte[] pdfBytes, string filePath)
    {
        File.WriteAllBytes(filePath, pdfBytes);
        Console.WriteLine($"Saved: {filePath}");
    }
}
// Simple user class with ID and HTML content
public class User
{
    public string Id { get; set; }
    public string HtmlContent { get; set; }
}
Imports System
Imports System.Collections.Concurrent
Imports System.Collections.Generic
Imports System.IO
Imports System.Threading.Tasks
Imports IronPdf
Public Class Program
	Private Shared pdfReports As New ConcurrentDictionary(Of String, Byte())()
	Shared Sub Main(ByVal args() As String)
		' Simulated user list with HTML content
		Dim users = New List(Of User) From {
			New User With {
				.Id = "user1",
				.HtmlContent = "<h1>Report for User 1</h1>"
			},
			New User With {
				.Id = "user2",
				.HtmlContent = "<h1>Report for User 2</h1>"
			},
			New User With {
				.Id = "user3",
				.HtmlContent = "<h1>Report for User 3</h1>"
			}
		}
		' Generate PDFs concurrently
		Dim renderer = New ChromePdfRenderer()
		Parallel.ForEach(users, Sub(user)
			Dim pdf = pdfReports.GetOrAdd(user.Id, Function(id)
				Dim pdfDoc = renderer.RenderHtmlAsPdf(user.HtmlContent)
				Return pdfDoc.BinaryData
			End Function)
			SaveToFile(pdf, $"{user.Id}.pdf")
		End Sub)
		Console.WriteLine("PDF generation complete.")
	End Sub
	' Utility method to write PDF binary data to file
	Private Shared Sub SaveToFile(ByVal pdfBytes() As Byte, ByVal filePath As String)
		File.WriteAllBytes(filePath, pdfBytes)
		Console.WriteLine($"Saved: {filePath}")
	End Sub
End Class
' Simple user class with ID and HTML content
Public Class User
	Public Property Id() As String
	Public Property HtmlContent() As String
End Class
$vbLabelText   $csharpLabel

Arquivos salvos

Dicionário Concorrente C# (Como funciona para desenvolvedores): Figura 2 - Arquivos de exemplo salvos conforme especificado

Exemplo de saída

Dicionário Concorrente em C# (Como funciona para desenvolvedores): Figura 3 - Exemplo de documento PDF

Análise do código

Este exemplo demonstra como combinar ConcurrentDictionary<TKey, TValue> Utilize o IronPDF para gerar PDFs de forma segura para múltiplos threads. É perfeito para aplicativos onde várias threads processam e armazenam arquivos PDF em cache simultaneamente.

Por que usar um ConcurrentDictionary?

  • Garante acesso seguro a pares de chave-valor em ambientes com múltiplas threads.
  • A função GetOrAdd() evita a geração de PDFs duplicados.
  • Não são necessárias fechaduras manuais — perfeito para alta concorrência. Como funciona

  • Uma lista de usuários, cada um com um ID e um HTML.
  • O Parallel.ForEach cria threads para gerar PDFs.
  • Cada thread usa GetOrAdd() para buscar ou criar o PDF.
  • O PDF é salvo usando o ID do usuário como nome do arquivo. Resumo

Este padrão é ideal quando:

Você está gerando PDFs para vários usuários ao mesmo tempo.

  • Você precisa de desempenho e segurança de threads. Você deseja concorrência limpa e confiável em C#.

Métodos de extensão e padrões de acesso

Embora o ConcurrentDictionary não exponha todos os recursos do LINQ, você ainda pode usar métodos de extensão para consultar valores:

var completedKeys = pdfReports.Keys.Where(k => k.StartsWith("done-")).ToList();
var completedKeys = pdfReports.Keys.Where(k => k.StartsWith("done-")).ToList();
Dim completedKeys = pdfReports.Keys.Where(Function(k) k.StartsWith("done-")).ToList()
$vbLabelText   $csharpLabel

No entanto, evite depender de elementos copiados durante a iteração, pois o dicionário pode mudar. Use .ToList() ou .ToArray() para trabalhar com um instantâneo, se necessário.

Conclusão: Segurança de threads aliada à automação de PDF

O Dicionário Concorrente<TKey, TValue> É ideal para cenários em que várias threads precisam ler/gravar pares de chave-valor simultaneamente, tornando-se um complemento perfeito para o IronPDF em aplicações multithread.

Seja para armazenar em cache PDFs renderizados, rastrear o status de tarefas ou evitar operações redundantes, o uso dessa coleção thread-safe garante que sua lógica seja escalável em termos de desempenho e confiabilidade.

Experimente o IronPDF hoje mesmo!

Pronto para criar aplicativos PDF de alto desempenho com total segurança de threads? Baixe uma versão de avaliação gratuita do IronPDF e experimente a geração perfeita de PDFs combinada com o poder do ConcurrentDictionary do C#.

Perguntas frequentes

Como um ConcurrentDictionary melhora o desempenho em aplicações C# multithread?

Um ConcurrentDictionary melhora o desempenho em aplicações C# multithread, permitindo que várias threads executem operações como inserções, atualizações e pesquisas simultaneamente, sem a necessidade de bloqueios externos, mantendo assim a integridade dos dados.

Qual a importância de usar o ConcurrentDictionary com o IronPDF?

A utilização do ConcurrentDictionary com o IronPDF é importante porque permite o gerenciamento seguro de dados em threads durante o processamento paralelo de PDFs, garantindo que a geração de PDFs seja eficiente e livre de conflitos de dados em ambientes multithread.

É possível usar o ConcurrentDictionary para gerenciar a geração simultânea de PDFs em C#?

Sim, o ConcurrentDictionary pode ser usado para gerenciar a geração simultânea de PDFs em C#, garantindo que as operações sejam tratadas com segurança em várias threads, melhorando a eficiência e a confiabilidade do processo de geração de PDFs.

Por que a segurança de threads é importante ao gerar PDFs em C#?

A segurança de threads é importante ao gerar PDFs em C# para evitar corrupção de dados e garantir uma saída consistente, especialmente quando várias threads estão envolvidas na criação e modificação dinâmica de documentos PDF.

Que operações podem ser realizadas simultaneamente usando ConcurrentDictionary?

Operações como inserções, atualizações, pesquisas e exclusões podem ser realizadas simultaneamente usando o ConcurrentDictionary, tornando-o ideal para aplicações de alto desempenho que exigem gerenciamento de dados thread-safe.

Como o IronPDF lida com operações simultâneas?

O IronPDF lida com operações simultâneas utilizando coleções thread-safe, como o ConcurrentDictionary, o que permite o processamento eficiente de PDFs e o gerenciamento de dados em várias threads sem comprometer a integridade dos dados.

É necessário implementar bloqueio externo ao usar ConcurrentDictionary?

Não, não é necessário implementar bloqueio externo ao usar o ConcurrentDictionary, pois ele foi projetado para ser inerentemente thread-safe, gerenciando operações concorrentes internamente.

Como os desenvolvedores podem otimizar o processamento de PDFs em aplicativos C#?

Os desenvolvedores podem otimizar o processamento de PDFs em aplicativos C# integrando coleções thread-safe, como ConcurrentDictionary, com bibliotecas como IronPDF, permitindo o processamento paralelo eficiente e confiável de documentos PDF.

Curtis Chau
Redator Técnico

Curtis Chau é bacharel em Ciência da Computação (Universidade Carleton) e se especializa em desenvolvimento front-end, com experiência em Node.js, TypeScript, JavaScript e React. Apaixonado por criar interfaces de usuário intuitivas e esteticamente agradáveis, Curtis gosta de trabalhar com frameworks modernos e criar manuais ...

Leia mais

Equipe de suporte de ferro

Estamos online 24 horas por dia, 5 dias por semana.
Bater papo
E-mail
Liga para mim