Skrivet av PTSD:
Hej
Kan någon lite smidigt förklara vad som är viktigt när det kommer till ämnet CPU kärnor och dess trådar?
Att kärnor klockas har jag förstått och att kärnor ofta har två trådar var.
Delas effekten av en kärna upp på två trådar eller har varje tråd full effekt.
När man pratar om hur många CPU's ett program kan nyttja menar man då trådar eller faktiska kärnor?
Jag har som exempel inte valt min hårdvara själv alls men när jag tittar under "Resource Monitor" så står det att jag har 8 olika CPU's och alla ligger ganska stabilt på 65%.
Får se om jag minns rätt från utbildningen för åtta år sen...
En tråd kan beskrivas som en kö med instruktioner som processorn ska utföra. Varje instruktion motsvaras i regel av ett kommando i Assembly, och ett statement i ett språk på högre nivå (C, Java, Python etc.) översätts oftast till en handfull instruktioner.
När processorn utför en instruktion så görs det i ett antal separata steg, några steg utförs alltid (vid alla instruktioner), men ibland är instruktioner så komplexa att de kräver några extra steg, helt beroende på vad processorn försöker utföra. När jag läste kursen i detta ämnet jobbade vi med 8- och 16-bitarsprocessorer där varje steg motsvarades av en klockpuls, och det tog mellan 3 och 8 steg att utföra en instruktion, alltså var hastigheten att uftföra kodinstruktioner som bäst en tredjedel av klockfrekvensen. Allt detta görs i en processorkärna som innehåller kretsar för att utföra logik/matte, lite lokal lagring för att kunna jobba med mer än ett värde samtidigt (3 * 5 blir svårt om det bara går att jobba med ett tal åt gången), styrenhet för att översätta en instruktionskod till interna elektriska signaler, samt ledningar mellan allt detta och för att få in och ut data ur kärnan.
Hyper Threading (som Intel kallar det när man kör flera trådar på en kärna) dök upp när någon kom på att den där cykeln av 3-8 steg (eller vad det kan motsvaras av på x86) har en viss effekt. Vissa komponenter i kärnan används vid vissa tidpunkter och väntar sedan bara på att nästa instruktion ska dyka upp, typ fem klockpulser senare. Idén gick ut på att börja utföra nästa instruktion innan föregående har avslutats, så att exempelvis steg 1 och steg 4 körs samtidigt. Detta förutsätter att komponenterna som behövs inte är (eller kommer bli) upptagna av den föregående instruktionen, men eftersom designern vet exakt hur varje given instruktion utförs går det att förutspå genom att bara läsa i förväg i kön av instruktioner.
Om jag minns rätt blir inte processorn exakt dubbelt så effektiv (vilket vi ser i task managern där vi plötsligt kan ha 8 logiska processorer (trådar) trots att vi bara har fyra kärnor), men jag har för mig att vissa kombinationer av instruktioner är mer effektiva än 2x, och andra inte. Jag kan tänka mig att 2x är en bra abstraktion. Dessutom simulerar det förhållandet mellan två instruktioner som körs samtidigt.
Det förutsätter nämligen att om instruktion A och B körs på samma kärna, B startar innan A är färdig, så kan inte B vara beroende av resultatet av A, alltså är det säkrast att programmerarna håller koll på vilka uppsättningar kod som kan köras samtidigt eller inte, och därmed dök konceptet om trådning upp inom programmering. Instruktioner som är beroende av tidigare resultat, eller i alla fall av att tidigare instruktioner utförts, körs i samma tråd. Om det är helsäkert att köra en annan uppsättning instruktioner oberoende av den första, så skapar programmet en ny tråd och placerar instruktionerna där.
Nu blir det lite mer komplicerat än så, för en tråd inom programmering är inte alltid 1:1 med en tråd i hårdvara. Operativsystemet placerar varje program som körs i separata processer, och har en funktion som växlar och prioriterar vilken process som ska få sina instruktioner körda på processorn. Därför kunde vi utan problem köra flera program samtidigt även med en enkärning processor utan flera trådar. När flera kärnor och trådar finns tillgängliga så försöker operativsystemet förstås dra nytta av det, men vi vet inte exakt vilket program som kommer köras på vilken kärna eller tråd vid ett givet tillfälle, det är upp till operativsystemet att optimera och fördela. Sista effekten av att programmera för flera trådar är att eftersom programmeraren inte har full kontroll över prioriteringen, så går det inte att förvänta sig att en tråd körs och når ett resultat före en annan, för att kunna göra det måste funktioner för att invänta andra trådar användas, och det blir direkt ännu mer komplicerat.
Rent intellektuellt är det mycket lättare att designa mjukvara som har en förutsägbar logisk följd av när vilka instruktioner utförs. Att programmera parallellt kan vara intuitivt och sjukt effektivt för vissa typer av uppgifter (att köra många oberoende datapunkter genom samma funktion), men på gränsen till omöjligt i andra (ett spel som största delen av tiden väntar på användarens input eller data från nätverket, och inte kan förbereda några händelser innan den inputen dyker upp). Därför är det en ständig debatt kring om exempelvis Threadripper är bättre att spela på än snabbaste i5-an. Spelets karaktär och hur väl programmerarna utnyttjar flera trådar blir i det fallet avgörande för skillnaden i prestanda.
Nu tar vi rast