CodeBlanks Logo Icon CodeBlanks

Birleştirme

C# kursu · Uzman · Ders 47/47

Tüm uzman konularını birleştirerek çalışan bir mini uygulama yazarsın.

Birleştirme

Son derste tüm parçaları birleştiriyoruz: Span ile kopyasız seviye ayrıştırma, Channel ile üretici-tüketici akışı, source generator simülasyonu ile DTO üretimi ve şimdi Parallel.ForEach ile çoklu iş parçacıklı sayım.

ProcessWithThreads metodu, tüm logları paralel işler ve Interlocked.Increment ile atomik bir sayaç tutar. Main artık tüm parçaları sırayla çağırır.

ProcessWithThreads metodu

ProcessWithThreads, bir static int processed alanını sıfırlar, Parallel.ForEach ile her logu paralel işler ve Interlocked.Increment(ref processed) ile atomik sayar. Sonra toplamı yazdırır.

processed statik bir alan olduğu için ref ile lambda içinden güvenle kullanılabilir. Çıktı deterministiktir: dört log varsa sonuç dört olur.

Uygulama ProcessWithThreads ekle ve birleştir

LogProcessor'a private static int processed; alanı ve public static void ProcessWithThreads(string[] logs) metodu ekle. Gövdede processed = 0; yap, System.Threading.Tasks.Parallel.ForEach(logs, _ => { System.Threading.Interlocked.Increment(ref processed); }) çağır, sonra Console.WriteLine($"işlenen: {processed}") yaz. Main'de en son LogProcessor.ProcessWithThreads(logs) çağır.

Örnek çözümü göster
ProcessWithThreads ekle. Main'de LogProcessor.ProcessWithThreads(logs);
Örnek çözüm:
using System;
using System.Linq;

static class LogProcessor
{
    public static int ParseLevel(string level)
    {
        return level switch
        {
            "INFO" => 0,
            "WARN" => 1,
            "ERROR" => 2,
            _ => -1
        };
    }

    public static int CountByLevel(string[] logs, int targetLevel)
    {
        int count = 0;
        foreach (var log in logs)
        {
            if (ParseLevel(log.Split(':')[0]) == targetLevel)
            {
                count++;
            }
        }
        return count;
    }

    public static string ParseWithSpan(ReadOnlySpan<char> log)
    {
        int colon = log.IndexOf(':');
        if (colon < 0) return "";
        return log.Slice(0, colon).ToString();
    }

    public static unsafe int UnsafeSum(int a, int b)
    {
        int* pa = &a;
        int* pb = &b;
        return *pa + *pb;
    }

    public static async System.Threading.Tasks.Task Run(string[] logs)
    {
        var channel = System.Threading.Channels.Channel.CreateUnbounded<string>();
        var counts = new System.Collections.Concurrent.ConcurrentDictionary<string, int>();
        foreach (var log in logs)
        {
            await channel.Writer.WriteAsync(log);
        }
        channel.Writer.Complete();
        await foreach (var log in channel.Reader.ReadAllAsync())
        {
            var level = ParseWithSpan(log.AsSpan());
            counts.AddOrUpdate(level, 1, (_, n) => n + 1);
        }
        foreach (var kvp in counts.OrderBy(k => k.Key))
        {
            Console.WriteLine($"{kvp.Key}: {kvp.Value}");
        }
        LogProcessor.ProcessWithThreads(logs);
    }
}

static class DtoGenerator
{
    public static System.Collections.Generic.List<(string Hint, string Source)> Sources { get; } = new();

    public static void AddSource(string hintName, string source)
    {
        Sources.Add((hintName, source));
    }

    public static void Generate(string[] typeNames)
    {
        foreach (var name in typeNames)
        {
            AddSource(name + ".g.cs", $"public class {name}Dto {{ }}");
        }
    }

    private static int processed;

    public static void ProcessWithThreads(string[] logs)
    {
        processed = 0;
        System.Threading.Tasks.Parallel.ForEach(logs, _ =>
        {
            System.Threading.Interlocked.Increment(ref processed);
        });
        Console.WriteLine($"işlenen: {processed}");
    }
}

class Program
{
    static void Main()
    {
        Console.WriteLine("LogProcessor iskeleti hazır");
        var logs = new[] { "INFO: a", "WARN: b", "INFO: c", "ERROR: d" };
        Console.WriteLine(LogProcessor.CountByLevel(logs, 0));
        Console.WriteLine(LogProcessor.ParseWithSpan("ERROR: disk".AsSpan()));
        Console.WriteLine(LogProcessor.UnsafeSum(3, 4));
        LogProcessor.Run(logs).Wait();
        DtoGenerator.Generate(new[] { "Info", "Warn", "Error" });
        foreach (var entry in DtoGenerator.Sources)
        {
            Console.WriteLine(entry.Hint);
        }
    }
}

Kendini test et

  1. Uzman konularını eşleştir

    Span<T>
    Bellek verimli parse
    Channel<T>
    Paralel akış
    Parallel.ForEach
    Çoklu iş parçacığı
  2. Projede tüm logların işlendiğini saymak için hangi sınıf kullanılır?

    • Interlocked (atomik sayaç)
    • StringBuilder
    • DateTime
    • Random
    Cevabı göster

    Interlocked (atomik sayaç) — Doğru. Interlocked atomik artırma yapar.

  3. Parallel.ForEach çağrısını tamamla

    Parallel.____(logs, _ => Interlocked.Increment(ref processed));
    Cevabı göster
    Parallel.ForEach(logs, _ => Interlocked.Increment(ref processed));

Uzman bölümündeki tüm dersler