Asynkron

💡 Vad är asynkron programmering?

Asynkron är som att multitaska - du kan göra flera saker samtidigt!

Tänk dig att du lagar middag. Istället för att stå och vänta på att pastan ska koka klart (10 minuter av ingenting), kan du samtidigt hacka grönsaker, sätta på såsen och diska. När pastan är klar så “piper” den och du vet att det är dags att hälla av vattnet.

Så fungerar async och await - din kod kan göra andra saker medan den väntar på att något ska bli klart!

🎯 TL;DR

Async = multitasking för kod. Din app svarar snabbare eftersom den inte “hänger sig” när den väntar. async Task + await = magiska nyckelord för att inte blockera UI:t.

📋 Efter att ha läst detta kommer du att kunna

  • Förstå skillnaden mellan sync och async kod 🔄
  • Använda async och await korrekt ✅
  • Veta när async är användbart (och när det INTE är det) 🤔
  • Undvika vanliga async-fällor 💣
  • Skriva responsiva applikationer 🚀

🔧 Grundprinciper

Princip 1: Blockera aldrig UI-tråden

Användare hatar när appar “fryser”. Async håller dem glada.

Princip 2: Vänta smart

Istället för att sitta och stirra på en laddningsskärm, gör något användbart.

Princip 3: Parallellism vs Concurrency

  • Concurrency: Flera tasks växlar mellan att köras
  • Parallellism: Flera tasks körs samtidigt på olika kärnor

💭 Tänk så här (Sync vs Async)

💬 Skillnaden mellan sync och async:


SYNC (Blockerar):
1. Ring API → Väntar... (5 sekunder)
2. UI fryser 🥶
3. Användaren blir arg 😠
4. Få svar → Fortsätt

ASYNC (Blockerar inte):
1. Ring API → Fortsätt direkt!
2. Gör andra saker medan vi väntar
3. UI fungerar fortfarande ✨
4. Få svar → Uppdatera UI

⚠️ Viktiga async-regler

  • async metoder returnerar Task eller Task<T> (ALDRIG void)
  • Använd await för att vänta på result
  • Async “smittar” - en async metod kan bara kallas från async metod
  • Undvik async void (bara för event handlers)
  • Ingen out eller ref parametrar i async metoder

🚀 Async i praktiken

🟢 Grundläggande async/await


// SYNC (Blockerar 5 sekunder)
public string GetWeatherSync()
{
    Thread.Sleep(5000); // Simulerar API-anrop
    return "Soligt, 25°C";
}

// ASYNC (Blockerar INTE)
public async Task<string> GetWeatherAsync()
{
    await Task.Delay(5000); // Simulerar API-anrop
    return "Soligt, 25°C";
}

// Användning:
public async Task<string> ShowWeatherAsync()
{
    // UI fungerar fortfarande under dessa 5 sekunder!
    string weather = await GetWeatherAsync();
    return $"Väder: {weather}";
}

🟡 HTTP-anrop med HttpClient


public class WeatherService
{
    private readonly HttpClient _httpClient;

    public WeatherService(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    // RÄTT sätt - använd async hela vägen
    public async Task<WeatherData> GetWeatherAsync(string city)
    {
        try
        {
            string url = $"https://api.weather.com/{city}";

            // Detta blockerar INTE UI:t!
            HttpResponseMessage response = await _httpClient.GetAsync(url);
            response.EnsureSuccessStatusCode();

            string json = await response.Content.ReadAsStringAsync();
            return JsonSerializer.Deserialize<WeatherData>(json);
        }
        catch (HttpRequestException ex)
        {
            // Hantera nätverksfel
            throw new WeatherServiceException($"Failed to get weather: {ex.Message}", ex);
        }
    }

    // FEL sätt - blockerar med .Result
    public WeatherData GetWeatherBad(string city)
    {
        return GetWeatherAsync(city).Result; // 🚨 DEADLOCK-risk!
    }
}

public class WeatherData
{
    public string City { get; set; }
    public int Temperature { get; set; }
    public string Description { get; set; }
}

🔴 Avancerat: Parallell exekvering


public class DataService
{
    public async Task<CombinedData> GetAllDataAsync()
    {
        // Starta alla tasks samtidigt (parallellt)
        Task<UserData> userTask = GetUserDataAsync();
        Task<OrderData> orderTask = GetOrderDataAsync();
        Task<WeatherData> weatherTask = GetWeatherDataAsync();

        // Vänta på att ALLA ska bli klara
        await Task.WhenAll(userTask, orderTask, weatherTask);

        // Nu är allt klart - hämta resultaten
        return new CombinedData
        {
            User = userTask.Result,
            Orders = orderTask.Result,
            Weather = weatherTask.Result
        };
    }

    // Alternativ: Vänta på första som blir klar
    public async Task<string> GetFastestResponseAsync()
    {
        Task<string> server1 = CallServer("https://server1.com");
        Task<string> server2 = CallServer("https://server2.com");
        Task<string> server3 = CallServer("https://server3.com");

        // Returnera första som svarar
        Task<string> firstCompleted = await Task.WhenAny(server1, server2, server3);
        return await firstCompleted;
    }

    private async Task<string> CallServer(string url)
    {
        using var client = new HttpClient();
        return await client.GetStringAsync(url);
    }
}

⚠️ Vanliga async-misstag

Misstag 1: async void


// 🚨 FEL - async void (bara för event handlers)
public async void SaveDataBad()
{
    await database.SaveAsync(data);
}

// ✅ RÄTT - async Task
public async Task SaveDataGood()
{
    await database.SaveAsync(data);
}

Misstag 2: Deadlock med .Result


// 🚨 FEL - kan orsaka deadlock
public void CallApi()
{
    var result = GetDataAsync().Result; // FARLIGT!
}

// ✅ RÄTT - använd async hela vägen
public async Task CallApiAsync()
{
    var result = await GetDataAsync();
}

Misstag 3: Fire-and-forget


// 🚨 FEL - ignorerar fel och completion
public void StartBackgroundWork()
{
    DoLongRunningWorkAsync(); // Ignoreras!
}

// ✅ RÄTT - hantera task korrekt
public async Task StartBackgroundWorkAsync()
{
    await DoLongRunningWorkAsync();
}

🔍 När ska du använda async?

✅ Använd async när:

  • HTTP-anrop (API:er, webb-requests)
  • Databasoperationer
  • Fil I/O (läsa/skriva filer)
  • Timer-operationer (Task.Delay)
  • UI-applikationer (hålla UI responsivt)

❌ Använd INTE async för:

  • CPU-intensiva beräkningar (använd Task.Run istället)
  • Snabba operationer (< 50ms)
  • När du inte har någon I/O
  • Bara för “att det låter coolt”

📚 Sammanfattning

Async/await är superkraft för responsiva appar:

  • async Task för metoder som inte returnerar värde
  • async Task<T> för metoder som returnerar värde
  • await för att vänta på async operationer
  • Aldrig async void (bara event handlers)
  • Async smittar - använd det hela vägen upp

🎯 Övningar

  1. 🟢 Grundläggande: Skriv en async metod som väntar 3 sekunder och returnerar ditt namn
  2. 🟡 Utmanande: Hämta data från 3 olika API:er parallellt med Task.WhenAll
  3. 🔴 Expert: Skapa en async metod som hanterar timeout och retry-logik

😄 Obligatorisk dad joke

Varför gillar async-metoder att multitaska?

För att de aldrig vill blocka någons tid! ⏰


Undersidor


    Upp

    Upp


    Licens: Apache 2.0 | © 2023 Marcus Medina, Campus Mölndal. Alla rättigheter förbehållna.
    Du får använda och modifiera detta verk enligt villkoren i Apache License, Version 2.0. Du får inte använda detta verk för kommersiella ändamål utan tillstånd från upphovsmannen.