Clean Blog

A Blog Theme by Stefan

Två nya utvecklare och utbildare

Kimmo Ahola och William Gross förstärker vårt gäng, båda fantastiska utvecklare med rötterna i Microsoft-plattform och med universiella kunskaper som gör att dom behärskar det mesta inom fullstackutveckling.


Vi söker en Utbildare IT-säkerhet och nätverk

Vi söker en Utbildare IT-säkerhet och nätverk


[Del 2] API Performance Tests: Java och Go

Nu jämför vi Go och Java, med fokus på prestanda och resursanvändning. Här är några viktiga takeaways från videon:

## 1. Go vs Java – Olika Styrkor
Go är extremt resurseffektivt och kan köras med minimalt minne (t.ex. 16-32 MB RAM). Det är ett statiskt kompilerat språk med låg overhead, vilket gör det perfekt för små, skalbara applikationer.

Java kräver mer minne (kunde inte ens starta med 16-32 MB) men har en JVM som kan optimera koden under körning (t.ex. HotSpot-optimeringar, inlining). I stora applikationer kan detta leda till bättre prestanda än statiskt kompilerade språk.

## 2. Virtual Threads (Project Loom) i Java
Från Java 21 introducerades virtuella trådar (Project Loom), vilket gör att Java kan hantera tusentals samtidiga anrop effektivt, liknande Go-rutiner.

I Go är parallellitet inbyggt med goroutines, medan Java tidigare behövde @Async eller liknande för att uppnå samma sak.

## 3. Testresultat
Go klarade ~2145 requests/sekund med låg resursanvändning.

Java (efter optimering) nådde ~914 requests/sekund, men krävde betydligt mer minne och CPU.

Med minimala resurser (16-32 MB RAM) startade inte Java ens, medan Go fungerade utan problem.

## 4. När Välja Go vs Java?
Välj Go om du behöver:

Extrem resurseffektivitet (mikrotjänster, serverless, embedded).

Enkel parallellitet med goroutines.

Snabb starttid (ingen JVM-startup).

Välj Java om du har:

Stora applikationer där JVM-runtime-optimeringar kan utnyttjas.

Tillgång till mycket RAM/CPU.

Behov av en mogen ekosystem (Spring, Hibernate, m.fl.).

## 5. Slutsats
“Det beror på” – Båda språken har sina styrkor.

Go vinner i låg-resursmiljöer (containrar, moln).

Java kan vara snabbare i högskaliga system med tillräckligt med resurser.


[Del 1] API Performance Tests del 1: Go vs ASP.NET & More

## Introduktion: Prestandatester av API:er i Olika Programmeringsspråk

Att välja rätt programmeringsspråk och ramverk för att bygga API:er är en fråga som ofta väcker diskussioner bland utvecklare. Vilket språk är snabbast? Vilket är mest resurssnålt? Och hur påverkar valet av språk och implementation prestandan under hög belastning? I denna artikel går vi igenom en serie prestandatester där samma API byggs i olika språk – med fokus på Go och ASP.NET (C#) – och körs i en modern molnmiljö med Kubernetes, Docker och övervakningsverktyg som Prometheus och Grafana. Vi undersöker mätvärden, flaskhalsar och lärdomar kring asynkron programmering, trådhantering och resursanvändning.

## Testupplägg: Samma API i Flera Språk

### API:ets Funktionalitet

För att skapa en rättvis jämförelse byggs ett och samma API i flera olika språk. API:et är enkelt: det har en endpoint (/players) som returnerar JSON-data. Under huven görs tre saker:

– **Deserialisering av JSON** – typiskt för många API:er.
– **Simulerat databas-anrop** – en fördröjning på 10 millisekunder för att efterlikna en databasfråga.
– **CPU-bound beräkning** – en klassisk Fibonacci-beräkning för att belasta processorn.

Detta ger en blandning av I/O-bound och CPU-bound arbetsuppgifter, vilket är representativt för många verkliga API:er.

### Miljö och Infrastruktur

För att säkerställa jämförbara resultat körs API:erna i ett Kubernetes-kluster i molnet. Klustret är litet och består av två virtuella maskiner. Varje API körs i en egen Docker-container, och resurser som CPU och minne begränsas explicit i deployment-filerna. Övervakning sker med CAdvisor, Prometheus och Grafana, och lasttestning görs med verktyget “hey” (ett Go-baserat lasttestningsprogram).

### Mätvärden: De Fyra “Golden Signals”

Vid prestandamätning av API:er fokuserar man ofta på fyra nyckelvärden, de så kallade “golden signals”:

– **Latency**: Hur lång tid tar det att få svar?
– **Traffic**: Hur många anrop per sekund klarar API:et?
– **Errors**: Hur många fel (t.ex. HTTP 500) uppstår?
– **Saturation**: Hur mycket CPU och minne används?

Dessa mätvärden visualiseras i Grafana-dashboards och analyseras för att identifiera flaskhalsar och styrkor i respektive implementation.

## Lasttestning och Mätmetodik
### Verktyg och Testparametrar

Lasttestningen sker med “hey”, där man kan ange antal anrop, antal samtidiga användare och anropsfrekvens. Ett typiskt test kan vara 1500 anrop med 50 samtidiga användare, där varje användare gör ett anrop per sekund. Resultaten analyseras med hjälp av percentiler (P50, P90, P99) för att förstå fördelningen av svarstider.

### Percentiler och Vad de Säger

– **P50**: Medianen – 50% av anropen är snabbare än detta värde.
– **P90**: 90% av anropen är snabbare än detta värde.
– **P99**: 99% av anropen är snabbare än detta värde.

Detta ger en mer nyanserad bild än bara medelvärde, särskilt när det gäller att förstå “long tail”-problem och spikar i svarstider.

### Infrastruktur: Kubernetes, Docker och Övervakning

#### Kubernetes-klustret
API:erna körs i ett Kubernetes-kluster, där varje implementation får en egen deployment och service. Ingress-kontrollers (NGINX) används för att routa trafik till rätt API. Resursbegränsningar (CPU och minne) sätts i deployment-filerna för att möjliggöra rättvis mätning av resursanvändning.

#### Övervakning med CAdvisor, Prometheus och Grafana
– **CAdvisor** samlar in data om alla containers.
– **Prometheus** hämtar och lagrar tidsseriedata från CAdvisor.
– **Grafana** används för att visualisera data i dashboards, t.ex. för CPU- och minnesanvändning samt latency och fel.

### Konfiguration och Automatisering

All konfiguration – från Dockerfiler till Kubernetes YAML-filer och Helm-skript – delas och kan återanvändas av andra som vill göra liknande tester. Det finns även tips om vanliga fallgropar, t.ex. eftersläpningar i rapporteringen mellan övervakningsverktygen.

#### Kodstruktur och Skillnader
Både Go och ASP.NET-implementationerna gör i grunden samma sak: deserialiserar JSON, simulerar ett databas-anrop och gör en CPU-bound beräkning. Men det finns viktiga skillnader i hur de hanterar asynkrona operationer och trådhantering.

##### ASP.NET (C#)
I C# används traditionellt Thread.Sleep för att simulera fördröjningar, men detta är problematiskt i en webbmiljö. Varje tråd som sover är otillgänglig för andra anrop, vilket snabbt leder till att trådpoolen tar slut under hög belastning. Lösningen är att använda asynkrona metoder med await Task.Delay, vilket frigör tråden under väntetiden och gör att fler samtidiga anrop kan hanteras.

##### Go
Go är designat från grunden för parallellism och samtidighet. Alla anrop till standardbiblioteket är redan asynkrona och icke-blockerande. Det finns ingen motsvarighet till await – det är inbyggt i språket och run-timen. Detta gör att Go-applikationer kan hantera mycket högre belastning utan att trådpoolen tar slut.

Exempel på Kodproblem och Optimering
I det första testet användes Thread.Sleep i C#-koden, vilket ledde till att API:et snabbt blev överbelastat och började returnera fel (HTTP 500). Efter att ha bytt till await Task.Delay förbättrades prestandan avsevärt, men Go-implementationen var fortfarande betydligt mer resurssnål och stabil under hög belastning.

#### Resultat: Prestanda och Resursanvändning
##### Go: Låg Resursanvändning och Hög Stabilitet
Go-API:et klarade 1500 anrop per sekund utan problem. CPU-användningen låg på ca 3,5% och minnesanvändningen på under 32% av den tilldelade limiten. Alla anrop returnerade HTTP 200, och svarstiderna var jämna och låga. Go:s inbyggda parallellism och låga runtime-overhead gör det mycket väl lämpat för högbelastade API:er.

##### ASP.NET (C#): Högre Footprint och Känsligare för Belastning
ASP.NET-API:et hade initialt stora problem med fel och överbelastning på grund av synkron trådblockering. Efter optimering med asynkrona anrop förbättrades resultatet, men CPU- och minnesanvändningen var fortfarande betydligt högre än för Go. Svarstiderna var mer varierande, och det uppstod fortfarande en del fel vid hög belastning.

##### Skillnader i Garbage Collection
Både Go och C# har garbage collectors, vilket ibland kan ge spikar i svarstider (latency). I Go är dessa spikar mindre påtagliga, medan C#-applikationen kan få större variationer i latency, särskilt under hög belastning. Rust, som saknar garbage collector, förväntas ha ännu jämnare latency (något som ska testas i kommande delar av serien).

### Lärdomar om Asynkron Programmering och Trådhantering
#### Varför är Asynkron Kod Viktigt?
I moderna webbapplikationer är det avgörande att inte blockera trådar i onödan. Synkrona fördröjningar (t.ex. Thread.Sleep) gör att trådpoolen snabbt tar slut, vilket leder till fel och dålig prestanda. Asynkrona metoder (t.ex. await Task.Delay i C#) frigör tråden under väntetiden och möjliggör högre samtidighet.

#### Go:s Fördelar
Go är designat för samtidighet och parallellism. Alla operationer i standardbiblioteket är redan asynkrona, och det finns ingen risk att “glömma” att använda await. Detta gör Go mycket robust under hög belastning och minskar risken för flaskhalsar relaterade till trådhantering.

#### C# och Andra C-baserade Språk
C#, Java och andra språk med rötter i C är designade för en tid då datorer hade en CPU och en kärna. För att hantera samtidighet har man lagt till asynkrona mönster och trådpooler, men det kräver att utvecklaren är medveten om och använder dessa korrekt. Annars riskerar man att snabbt slå i taket för vad applikationen klarar av.

#### Resursbegränsningar och Mätning
Varför Sätta Limits?
Genom att sätta explicita begränsningar på CPU och minne i Kubernetes kan man mäta hur mycket resurser varje implementation faktiskt kräver. Detta är viktigt för att kunna jämföra olika språk och ramverk på ett rättvist sätt.

#### Hur Tolkade Vi Graferna?
I Grafana visualiserades både CPU- och minnesanvändning som procent av den tilldelade limiten. Detta gör det enkelt att se vilken implementation som är mest resurssnål och hur nära man är att slå i taket för tilldelade resurser.

### Slutsatser och Rekommendationer
#### Go: Perfekt för Högbelastade API:er
Go visade sig vara extremt resurssnålt och stabilt under hög belastning. Det är ett utmärkt val för API:er som förväntas hantera många samtidiga användare och höga anropsfrekvenser. Den inbyggda parallellismen och låga runtime-overheaden gör att Go-applikationer kan köras effektivt även på små servrar.

#### ASP.NET (C#): Bra, men Kräver Optimering
ASP.NET är ett moget och kraftfullt ramverk, men kräver att man skriver asynkron kod för att klara hög belastning. Även med optimeringar är resursförbrukningen högre än för Go, och det finns en större risk för flaskhalsar vid mycket hög samtidighet. För många applikationer är detta dock inget problem, särskilt om belastningen är måttlig.

#### Välj Språk efter Behov
Det finns ingen “one size fits all”. Om din applikation förväntas hantera extremt hög last och du vill minimera infrastrukturkostnader kan Go vara det bästa valet. Om du redan har en stor kodbas i C# och belastningen är rimlig fungerar ASP.NET utmärkt, förutsatt att du skriver asynkron kod.

#### Mät, Mät och Mät
Oavsett språk är det avgörande att mäta och övervaka din applikation under realistisk last. Använd verktyg som Prometheus och Grafana för att få insikt i resursanvändning, svarstider och fel. Testa olika implementationer och optimera utifrån faktiska mätvärden, inte magkänsla.

## Nästa Steg: Fler Språk och Djupare Analyser
Denna artikel är första delen i en serie där fler språk (Java, Python, Rust m.fl.) kommer att testas på samma sätt. Vi kommer även att undersöka hur skillnaderna ser ut vid mer “normala” laster (t.ex. 10–30 anrop per sekund) och vilka optimeringar som kan göras i respektive språk och ramverk.

Följ med i nästa del för djupare analyser, fler jämförelser och praktiska tips för att bygga snabba, skalbara och resurssnåla API:er – oavsett vilket språk du väljer!


Vi växer och blir bredare

Vi fortsätter växa. Med målet att samla de bästa och mest engagerade utbildarna så är våra tillskott Yayha Hussein och Zhengyao Jiang helt klockrena i vårt team.

Yayha är Javaexperten som jobbat massor med DevOps, IT Säkerhet och Cloud (AWS mm) och Zen (Zhengyao) är vår data engineer med djupa kunskaper rörande allt inom databaser/business intelligence och dataflöden.

Detta innebär också att vi fortsätter bredda vår kompetens och vårt erbjudande. Vi brukar kunna lösa de flesta kursförfrågningarna !


Vad gör vi hösten 2024

Ok, hösten 2024 har kommit igång, sedan länge faktiskt, vi är redan varma i kläderna med bland annat dessa kunder

Plushögskolan i Västerås
– Python för AI utvecklare, två årskullar, allt från grunder i Python till avancerad Python, databas, AI och maskininlärning

KYH
– .NET Systemutvecklare en ny klass; bland annat C# och databaser

EduGrade
.NET Systemutvecklare med AI, en ny klass här med; bland annat C# och databaser

Nackademin
– Java Devops och Java IT Säkerhet
– IOT programmet med Java, C/C++, Datastrukturer och algoritmer, samt IT Säkerhet

YHAkademin
– Cloud Native

Sen, redan i oktober blir det ännu fler nya och nygamla leveranser och efter jul väntar spännande kurser med bla Jensen och MedieInstitutet.


Förnyade och nya förtroenden för hösten

Vi har en massa spännande åtaganden att jobba med i höst, bland annat:

– förnyat förtroende från KYH avseende .NET Systemutvecklare
– Python och Databasteknik med Plushögskolan i Västerås som tidigare nämnts
– Java med STI
– Embedded Systems med Yrkesakademin
– Cloud med Go, Python och Kubernetes med Yrkesakademin
– Javascript * 2 samt IT Säkerhet med TUC
– Java * 2 AWS Cloud samt Webbutveckling med Jensen

Hur ska vi hinna allt undrar man. Kanske dags för ännu en kloning ?


4 nya kursavtal med STI

Java hos STI

Hösten och vintern 2023/2024 kommer vi köra Java på STI igen! Ska bli så kul

Vi utbildar på kurserna Testdriven utveckling, Molntjänster, Databashantering och Webservices i Java


printf format referens

# printf

“`
int printf ( const char * format, … );
“`

## Skriver formatterad data till stdout (console om ej redirected)

Skriver C strängen som parametern *format* pekar på. Om *format* innehåller format specifiers (sekvenser som börjar med *%* ) så kommer argument på slutet stoppas in på respektive plats (by index) och byta ut sess dpecifier.

## Parametrar

### format
C sträng som innehåller texten som ska skrivas till konsolen (stdout)
Format specifiers är optional, och dessa kan dessutiom innehålla ytterligare information:

En format specifier följer detta mönster:

%[flags][width][.precision][length]specifier

**specifier** – delen är den mest signifikanta, eftersom det avser datatypen

|specifier|Output|Example
|—|—|
|d or i |Signed decimal integer| 900
|u| Unsigned decimal integer |4511
|o| Unsigned octal |601
|x| Unsigned hexadecimal integer |8fa
|X| Unsigned hexadecimal integer (uppercase) |8FA
|f| Decimal floating point, lowercase |492.65
|F| Decimal floating point, uppercase |492.65
|e| Scientific notation (mantissa/exponent), lowercase |4.9265e+2
|E| Scientific notation (mantissa/exponent), uppercase |4.9265E+2
|g| Use the shortest representation: %e or %f |492.65
|G| Use the shortest representation: %E or %F |492.65
|a| Hexadecimal floating point, lowercase |-0xc.90fep-2
|A| Hexadecimal floating point, uppercase |-0XC.90FEP-2
|c| Character |a
|s| String of characters |sample
|p| Pointer address |b8000000
|n| Nothing printed.The corresponding argument must be a pointer to a signed int. The number of characters written so far is stored in the pointed location. |
|%| A % followed by another % character will write a single % to the stream. |%

Format specifiern kan också innehålla delarna: flags, width, .precision och modifiers (i den ordningen)

|flags|description|
|—|—|
|-| Vänster-justera inom givna fältets bredd. Högerjustering är default|
|+| Sätt ett plus eller minus framför tal () . Default = endast negativa får ett prefix (minus såklart)|
|(space)| Om inget plus eller minus ska skrivas sätt ett dett blanktecken (space) innan|
|#| Används med o, x eller X specifiers the value is preceeded with 0, 0x or 0X respectively for values different than zero.
Used with a, A, e, E, f, F, g or G it forces the written output to contain a decimal point even if no more digits follow. By default, if no digits follow, no decimal point is written.|
|0| Left-pads the number with zeroes (0) instead of spaces when padding is specified (see width sub-specifier).|

|width| description|
|—|—|
|(number)| Minsta antalet tecken som ska skrivas ut. Om antalet tecken är färre än detta nummer så kommer resultatet paddas med blanktecken.OBS: Värder trunkueras dock aldrig |
| * | Bredden specificeras inte i formatsträngen utan som ytterligare ett heltalsvärde som kommer innan värdet som ska formatteras|

| .precision | description|
|—|—|
|.number|För integer (heltal) (d, i, o, u, x, X): precision specificerar det minsta antalet tecken som sla skrivas. Om antalet tecken är färre än detta nummer så kommer resultatet paddas (utfyllas) med nollor i början. Värdet trunkeras aldrig även om resultatet är längre. Precision “0” betyder att inget tecken skrivs för värdet 0.
För a, A, e, E, f och F specifiers betyder detta antalet siffror som ska skrivas efter decimalpunkten ( default = 6 decimaler).
För g och G specifiers: maximala antalet signifikanta siffror som ska skrivas.
För s: maximalt antal tecken som ska skrivas. Default = alla tecken till null hittas skrivs ut
|
| * | Precisionen specificeras inte i formatsträngen utan som ytterligare ett heltalsvärde som kommer innan värdet som ska formatteras.|

The length sub-specifier modifies the length of the data type. This is a chart showing the types used to interpret the corresponding arguments with and without length specifier (if a different type is used, the proper type promotion or conversion is performed, if allowed):

**specifiers**

|length|d i |u o x X |f F e E g G a A |c| s| p| n|
|—|—|—|—|—|—|—|—|
|(none)|int|unsigned int|double|int| char* | void* | int* |
|hh| signed char |unsigned char|||| signed char* |
|h| short int| unsigned short||||| int short int* |
|l| long int |unsigned long int|| wint_t| wchar_t* || long int* |
|ll| long long int |unsigned long long int|||| long long int* |
|j| intmax_t| uintmax_t|||| intmax_t* |
|z| size_t| size_t|||| size_t* |
|t| ptrdiff_t |ptrdiff_t|||| ptrdiff_t* |
|L||| long double ||||

## Returnerar

Om det går bra, returneras totala antalet tecken som skrivits
Om fel returneras ett negativt tal och ferror sätts

## Exempel

“`
/* printf example */
#include

int main()
{
printf (“Characters: %c %c \n”, ‘a’, 65);
printf (“Decimals: %d %ld\n”, 1977, 650000L);
printf (“Preceding with blanks: %10d \n”, 1977);
printf (“Preceding with zeros: %010d \n”, 1977);
printf (“Some different radices: %d %x %o %#x %#o \n”, 100, 100, 100, 100, 100);
printf (“floats: %4.2f %+.0e %E \n”, 3.1416, 3.1416, 3.1416);
printf (“Width trick: %*d \n”, 5, 10);
printf (“%s \n”, “A string”);
return 0;
}
“`

**Output**
“`
Characters: a A
Decimals: 1977 650000
Preceding with blanks: 1977
Preceding with zeros: 0000001977
Some different radices: 100 64 144 0x64 0144
floats: 3.14 +3e+000 3.141600E+000
Width trick: 10
A string
“`


Ännu mera Python i Västerås

Vi har redan nu gjort klart med vår favoritkund – Plushögskolan Västerås – gällande deras YH-utbildning: Pythonutvecklare med AI inriktning.

Vi har precis avtalat om dessa kurser

  • Examensarbete våren 2023
  • Effektiv Pythonprogrammering hösten 2023
  • Objektorienterad Python hösten 2023
  • Databasteknik MySQL hösten 2023
  • Webbramverk våren 2024

Fantastiskt kul att få förnyat förtroende såklart och vi trivs väldigt bra i rollen att forma nya utvecklare och hjälpa studenter in i nya, fina karriärer-