Gå til indholdet

Async filhåndtering

Vi har tidligere set på de synkrone metoder til at arbejde med filer og mapper, men .NET har også understøttelse for asynkron I/O.

File og Directory

Både de statiske metoder på File og Directory, samt stream har async metoder. Med async/await er det rimelige simpel kode - her er lidt eksempler:

// Setup
string fil1 = @"c:\temp\f1.txt";
string fil2 = @"c:\temp\f2.txt";
System.IO.File.WriteAllText(fil1, "123");
System.IO.File.WriteAllText(fil2, "456");

string indhold = HentIndholdAsync(fil1, fil2).Result;
Console.WriteLine(indhold);

async Task<string> HentIndholdAsync(string f1, string f2)
{
    Task<string> r1 = System.IO.File.ReadAllTextAsync(f1);
    Task<string> r2 = System.IO.File.ReadAllTextAsync(f2);
    await Task.WhenAll(r1, r2);
    return r1.Result + r2.Result;
}

Async streams

Async streams er en feature fra C# 8.0, og kan bruges til at læse fra en stream asynkront. Her er et eksempel:

// Setup
string fil1 = @"c:\temp\f1.txt";
string fil2 = @"c:\temp\f2.txt";
await SkrivTilFilAsync(fil1, "123");
await SkrivTilFilAsync(fil2, "456");

async Task SkrivTilFilAsync(string filsti, string indhold)
{
    // Brug af async 'using' statement til automatisk at frigive StreamWriter-ressourcen
    await using (var writer = new StreamWriter(filsti, append: false))
    {
        await writer.WriteLineAsync(indhold);
        // Ingen eksplicit kald til Close nødvendig pga. 'await using'
    }
}


string indhold = HentIndholdAsync(fil1, fil2).Result;
Console.WriteLine(indhold);

async Task<string> HentIndholdAsync(string f1, string f2)
{
    // Asynkront læser indholdet fra to filer og returnerer summen af deres indhold
    string indhold1, indhold2;
    using (var sr1 = System.IO.File.OpenText(f1))
    {
        indhold1 = await sr1.ReadToEndAsync();
    }

    using (var sr2 = System.IO.File.OpenText(f2))
    {
        indhold2 = await sr2.ReadToEndAsync();
    }

    return indhold1 + indhold2;
}
/*
 ---------- Output: ----------

123456

*/

Opgaver

Asynkrone Enumerationer

Asynkrone enumerationer, introduceret med C# 8.0, tilføjer en ny dimension til asynkron programmering i .NET ved at tillade asynkron iteration over streams af data. Dette er særligt nyttigt i scenarier, hvor data produceres eller forbruges asynkront, for eksempel ved læsning fra en fil, netværksressource eller database, hvor data ikke er umiddelbart tilgængelige.

Asynkrone enumerationer udnytter IAsyncEnumerable<T> interface og await foreach-syntaksen til at iterere over data asynkront. Dette gør det muligt at afvente på hvert element i en samling, mens det bliver tilgængeligt, hvilket kan forbedre applikationens responsivitet og effektivitet ved at reducere blokerende opkald.

For at definere en metode, der returnerer en asynkron enumeration, skal du angive returtypen som IAsyncEnumerable<T>. Inden i metoden kan du bruge yield return-statementet til at returnere elementer et ad gangen, som du ville i en synkron enumerator, men med den tilføjede mulighed for at afvente asynkrone operationer.

Her er et eksempel på, hvordan du kan bruge asynkrone enumerationer:

public async IAsyncEnumerable<int> GenererTalAsynkront(int antal)
{
    for (int i = 0; i < antal; i++)
    {
        await Task.Delay(100); // Simulerer en asynkron operation
        yield return i;
    }
}

For at forbruge en asynkron enumeration, kan du bruge await foreach-syntaksen:

await foreach (var tal in GenererTalAsynkront(5))
{
    Console.WriteLine(tal);
}

Der er en del fordele ved at bruge asynkrone enumerationer, herunder:

  • Forbedret Responsivitet: Ved at tillade asynkron iteration, kan applikationer forblive responsive, selv når de venter på data.
  • Effektivitet: Reducerer behovet for at indlæse alle data i hukommelsen på én gang, hvilket kan være særligt nyttigt for store datasæt.
  • Simpel Syntaks: await foreach gør det let at skrive kode, der arbejder med asynkron datastrømme.