Googles Go verkar vara ett riktigt grymt språk!

Permalänk
Avstängd

Googles Go verkar vara ett riktigt grymt språk!

Nån som sysslat lite med Go? Det är de gamla gubbarna som skapat det (folket bakom Unix, C, Plan9, etc - och liknande saker, dvs riktigt tungt respekterade saker). C är ju väldigt litet och elegant, och Go har lite grand av C känslan. Sen kan man programmera objektorienterad stil, trots att Go inte är objektorienterat. Det som sticker ut, är att Go är till för att hantera parallella (concurrent) saker från designen. Parallellmodellen verkar påminna en hel del om Erlangs framgångsrika modell. Go är mycket litet, elegant och parallellt. Verkar bli en riktig höjdare. Många som sysslat med Python går över till Go. Go är mycket lättare än C++ också, och kompilerar mycket snabbt.
http://golangtutorials.blogspot.se/2011/05/table-of-contents....
Asgrymt språk.

Permalänk
Medlem

Inte hunnit hoppa in på Go ännu men ska definitivt börja använda det när jag får tiden att sätta mig in i det!

Såg att du inte hade en länk till själva hemsidan så jag länkar väl då

http://golang.org/

Visa signatur
Permalänk
Medlem

Jag har skrivit lite små saker i go. Som webserver för long polling ajax etc.

Tycker Go är sjukt smidigt faktiskt. Speciellt att prata mellan trådar.

Permalänk
Avstängd

Jag hoppas alla går över till Go istället för C++ som är helt obegripligt stort. Python är litet och enkelt och elegant, och Go påminner lite om Python.

EDIT: Lite kritik. Go har inte MapReduce. Men det finns bibliotek för det:
http://dan.bravender.us/2009/11/24/MapReduce_for_Go.html

Här är en bra förklaring om funktionell programmering och MapReduce:
http://www.joelonsoftware.com/items/2006/08/01.html

Permalänk
Datavetare

Go är definitivt ett riktigt trevligt språk. De som designade språket ville skapa något som har många av fördelarna från dynamiskt typade skriptspråk (duck-typing) men ändå är ett starkt- och statiskt-typat kompilerat språk för systemprogrammering (i.e. samma målgrupp som bl.a. C, C++, Java och C#).

Rob Pike, som är expert på concurrent-programming, brukar vara väldigt noga att påpeka att Go är ett språk designat för just concurrent-programming och inte för parallel-programming. Det är lätt att blanda ihop dessa två.

Concurrent-programming är ett sätt att strukturerar sitt program och det tenderar att fungera extremt väl i program med massiv I/O-last (back-end system). Concurrent-programming är definitivt väldigt användbart i enkeltrådade program och på system som bara har en CPU-tråd, så ett sådant program behöver inte alls exekverar parallellt.

Parallel-programming är i stället ett mål att maximera effekten av system med många CPU-kärnor, typiska användningsområden här är high-performance-computing. Visst kan man använda Go även här, men C, C++ och Fortran med tillägg som Cilk+ eller OpenMP är nog bättre val här. Visst kan man uttrycka instruktions-parallellism i Go (går även i C#4 och Java7), men i Cilk+ kan man även uttrycka data-parallellism vilket gör det väldigt enkelt för kompilatorn att använda sig av SSE/AVX (något som överhuvudtaget inte går i C# och Java för tillfället).

De som designade Go må jobba på Google, men det är inte ett språk som kontrolleras av Google då språk, kompilator och standardbibliotek är släppt under BSD-licens. D.v.s. man får göra precis vad man vill, inklusive stoppa in det i egna projekt som man inte gör OpenSource!

Just nu finns det två kompilatorer för Go, en med namnet "gc" som är den man hittar på den officiella sidan för språket Go. Den andra är gccgo som är en "front-end" till gcc. Gccgo kan enkelt installeras via pakethanteraren om man kör Ubuntu, Fedora eller liknande. Gccgo tenderar att generera binärer som presterar bättre än de binärer man får med gc om problemet är CPU-bundent, är problemet I/O-bundent spelar kompilatorn sällan någon större roll.

Även om de flesta som använder Go nog kör det på Linux så har "gc" kompilator även stöd för Windows, och stödet är faktiskt riktigt bra. I Windows NT kärnan finns det något som kallas I/O Completion Ports, en finess som gör det möjligt att utveckla I/O-intensiva program som skalar väldigt bra. Det går att använda denna finess även i .Net och Java6/7, men det används inte de funktioner som folk oftast kör med och att använda det leder till lite mer komplicerade program. I Go används det alltid utan att man ens behöver tänka på det!

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

Permalänk
Datavetare

Ett litet smakprov på hur man kan använda Go för att uttrycka instruktions-parallellism, lägger även med motsvarande funktion för C# och Java som jämförelse.

Go

package main import ( "runtime" "flag" "fmt" ) const PARALLEL_THRESH = 30 func fib(n uint64) uint64 { if n < 2 { return n } return fib(n - 1) + fib(n - 2) } func parallelFib(n uint64) uint64 { if n < PARALLEL_THRESH { return fib(n) } n2Future := make(chan uint64) go func() { n2Future<- parallelFib(n - 2) }() return parallelFib(n - 1) + <-n2Future } func main() { c := flag.Int("c", 2, "Concurrency level") n := flag.Int("n", 30, "Argument to Fibonacci") flag.Parse() runtime.GOMAXPROCS(*c) fmt.Printf("fib(%v) = %v\n", *n, parallelFib(uint64(*n))) }

Dold text

Java

import java.util.concurrent.*; public class Fib extends RecursiveTask<Long> { protected static final int THREADS = 8; protected static final int PARALLEL_THRESH = 30; final long n; long result; public Fib(long n) { this.n = n; } protected long computeSerial(long n) { if (n <= 1) return new Long(n); return computeSerial(n - 1) + computeSerial(n - 2); } protected Long compute() { if (n < PARALLEL_THRESH) return new Long(computeSerial(n)); Fib f2 = new Fib(n - 2); f2.fork(); return new Fib(n - 1).compute() + f2.join(); } public static void main(String[] args) { if (args.length != 1) { System.err.println("Usage: Fib N"); System.exit(1); } long n = Long.parseLong(args[0]); System.out.format("fib(%d) = %d\n", n, new ForkJoinPool(THREADS).invoke(new Fib(n))); } }

Dold text

C#

using System; using System.Threading.Tasks; class Program { const ulong PARALLEL_THRESH = 30; public static ulong Fib(ulong n) { if (n < 2) return n; return Fib(n - 1) + Fib(n - 2); } public static ulong ParallelFib(ulong n) { if (n < PARALLEL_THRESH) return Fib(n); var taskN2 = Task.Factory.StartNew(() => ParallelFib(n - 2)); return ParallelFib(n - 1) + taskN2.Result; } public static void Main(string[] args) { const ulong N = 47; Console.WriteLine("fib({0}) = {1}", N, ParallelFib(N)); } }

Dold text

Detta är ett väldigt ineffektivt sätt att beräkna Fibonacci, men det är populärt ändå. Dels är det en direktöversättning av den matematiska definitionen, dels så är det ett enkelt exempel som innehåller massor med potentiellt instruktions-parallellism vilket gör det till en bra "show off" för dessa finesser.

På Win8 (laptop med i7-2760QM, 4 kärnor med HT) får man följande resultat av att köra detta:
Fallet med 2(HT) är när jag begränsat programmet till att köra på samma CPU-kärna men på båda CPU-trådarna.

Windows 8 Go fib(47) CPUs Elapsed Speedup 1 24.825 x1.00 2(HT) 19.371 x1.28 2 12.740 x1.95 3 8.640 x2.87 4 6.915 x3.59 8 6.118 x4.06 Windows 8 C# (VS2012) fib(47) CPUs Elapsed Speedup 1 34.939 x1.00 2(HT) 32.002 x1.09 2 17.657 x1.98 3 12.532 x2.79 4 10.204 x3.42 8 9.141 x3.82 Windows 8 Java (JDK7) fib(47) CPUs Elapsed Speedup 1 13.704 x1.00 2(HT) 12.157 x1.13 2 6.954 x1.97 3 4.891 x2.80 4 3.719 x3.68 8 3.500 x3.92

Dold text

Java7 är snabbast men Go skalar bäst från 1 CPU-tråd till 8 CPU-trådar. Lite förvånande att Microsoft eget språk körandes på deras eget OS är klart långsammast och skalar även sämst...

Då detta är väldigt "snällt" vad det gäller parallellism så skalar det väl, här är resultatet på en Linux server med 4st 8-kärniga Xeons (totalt 32-kärnor och 64-trådar)

4x 8-core Xeon Ubuntu 12.04 Java7 (OpenJDK) fib(50) CPUs Elapsed Speedup 1 59.084 x1.00 8 7.783 x7.59 32 2.319 x25.5 64 2.091 x28.3 Ubuntu 12.04 Go 1.1.1 fib(50) CPUs Elapsed Speedup 1 112.502 x1.00 8 14.390 x7.82 32 4.393 x25.6 64 3.058 x36.8 Ubuntu 12.04 gccgo 4.7 fib(50) CPUs Elapsed Speedup 1 45.805 x1.00 8 6.076 x7.54 32 2.004 x22.8 64 1.569 x29.2

Dold text

Även på Linux är Java7 snabbare än "gc" 1.1.1, men här hade jag även gccgo 4.7 installerat och det skalar ungefär som Java7 men lite mer än 30% snabbare! Inte så illa med tanke på att Java har optimerats under 20 års tid och Go släpptes officiellt våren 2012!

Och detta är på CPU-bundna saker, något som designerna av Go specifikt säger inte är huvudmålet med språket. Har skrivit en del nätverks-intensiva saker i Go och det har typiskt varit 10-100 gånger snabbare än motsvarande program skrivet i Java eller C++. Motsvarande i bemärkelsen: så som en expert i respektive språk skulle välja att skriva, jag vet hur Go är implementerat "under huven" och rent teoretiskt skulle jag kunna skriva ett C/C++ (och det borde även vara möjligt i Java med NIO) som beter på samma sätt. Grejen är att det är väldigt lätt att skriva ett sådan program i Go, det skulle vara extremt svårt att följa logiken i ett C/C++/Java program som, sett från OS:et, fungerar på samma sätt.

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

Permalänk
Medlem

Vill bara tacka för att ni tar er tid att presentera språket på ett (i mitt tycke) bra sätt.

Permalänk
Avstängd

Jag håller med, bra genomgång där utav virtual_void. Jag fick upp ögonen för Go, när du pratade om det i en annan tråd, och du hade skrivit en webserver i det. Började checka upp språket efter ditt inlägg.

En fråga. Speedup med 4 cores och 8 trådar, blir runt 4x och inte 8x. Du har ju 8 trådar, så man kanske kan vänta sig en bättre speedup? Intel har ju fusk trådar med sin HT, så då kanske det bara blir 4 trådar som kör egentligen? Men en 4 kärnig AMD har ju 8 "riktiga" trådar, som AMD brandar som 8 cores. Så då kanske det kan vara så att AMD får ut 8x speedup, trots att de har 4 cores (eftersom AMD har 8 "riktiga" trådar)? Och Intel får ut 4x speedup, pga de har klena HT trådar (som inte är riktiga trådar)? Kan du köra samma program på en AMD cpu med 8 cores (dvs 4 cores och 8 trådar)?

Permalänk
Datavetare
Skrivet av saddam:

Jag håller med, bra genomgång där utav virtual_void. Jag fick upp ögonen för Go, när du pratade om det i en annan tråd, och du hade skrivit en webserver i det. Började checka upp språket efter ditt inlägg.

En fråga. Speedup med 4 cores och 8 trådar, blir runt 4x och inte 8x. Du har ju 8 trådar, så man kanske kan vänta sig en bättre speedup? Intel har ju fusk trådar med sin HT, så då kanske det bara blir 4 trådar som kör egentligen? Men en 4 kärnig AMD har ju 8 "riktiga" trådar, som AMD brandar som 8 cores. Så då kanske det kan vara så att AMD får ut 8x speedup, trots att de har 4 cores (eftersom AMD har 8 "riktiga" trådar)? Och Intel får ut 4x speedup, pga de har klena HT trådar (som inte är riktiga trådar)? Kan du köra samma program på en AMD cpu med 8 cores (dvs 4 cores och 8 trådar)?

Skrev i inlägget att jag körde på en "i7-2760QM, 4 kärnor med HT", d.v.s. det är bara 4 "riktiga" kärnor men det är 8 CPU-trådar. Tittar du i stället på resultatet på Xeon-maskinen så är det nära nog linjär skalning till 8 kärnor. Att det inte fortsätter skala linjärt på Xeon-maskinen har flera anledningar, men viktigast är att jag löser ett problem och sprider ut det över många CPU-trådar. 4 CPU-chip betyder också 4 NUMA-zoner och det är sällan en bra idé att sprida ut en och samma beräkning över flera NUMA-zoner då det är väldigt dyrt att jobba mot "fel" NUMA-zon (bara en NUMA-zon som är "lokal" för varje CPU-chip).

Har tyvärr inte tillgång till någon Bulldozer eller Piledriver AMD
Men skulle gärna veta hur det skalar på en sådan!

Så mitt resultat var kanske lite otydligt för 8 CPU-trådar på i7-2760 samt 64 CPU-trådar på Xeon-maskinen, i båda dessa fall används alla CPU-trådar vilket betyder att båda hypertrådarna på varje kärna används. Alla övriga resultat utom de märkta 2(HT) är gjorda så att man bara använder den ena tråden i varje fysisk kärna.

På Linux gör man detta via taskset <mask>

$ time taskset <cpu-mask> <program_to_bench>

och på Windows finns det lite olika sätt, jag vill använda något form av shell och då kan man göra detta

Installera Cygwin och kör

$ cmd.exe /C start /affinity <cpu-mask> bash -c "time <program_to_bench>; read"

En liten luring här är att <cpu-mask> fungera olika på Windows och Linux... Har jag en 2-kärning CPU med HT så numrerar Windows

bit0=cpu0/thread0 bit1=cpu0/thread1 bit2=cpu1/thread0 bit3=cpu1/thread1

medan Linux numrerar

bit0=cpu0/thread0 bit1=cpu1/thread0 bit2=cpu0/thread1 bit3=cpu1/thread1

Men man ser rätt snabbt på resultatet mellan 1 CPU-tråd och 2 CPU-trådar om man använt två olika CPU-kärnor eller använt två HT på samma kärna. Denna typ av jämförelse skulle vara intressant på AMDs moduler så man fick bättre grepp på just hur nära en modul faktiskt är två "riktiga" kärnor, i alla fall i program som är väldigt snälla som detta. De tester man läser på nätet (inklusive SweC) jämför bara 1 CPU-tråd och alla CPU-trådar. Det man vill jämföra är 1 CPU-tråd med 2 CPU-trådar där man i ena fallet kör på olika fysiska kärnor och det andra fallet när man kör på samma fysiska kärna/modul.

Edit: och en till sak man måste ha i åtanke, framförallt när man kör på en modern laptop, är att CPU-frekvensen inte är konstant! Ju fler kärnor man använder, ju mindre "turbo boost" får man. Tar man även med det i åtanke så är det väldigt nära helt linjär skalning för Go-programmet. Den laptop jag körde med är en "desktop-replacement" så den har rätt väl tilltagen kylning och klockar sällan ner sig under 3.0GHz (men det händer). Max boost är 3.4GHz har jag för mig.

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

Permalänk
Medlem

Ska nog kanske programmera om min HTTP-"SPIDER" (mer en massnerladdare av URLer då den inte spindlar eggentligen) i Go när det är lite mindre stressigt (min katt ska avlivas och en kompis ska släppa en ny site som han behöver lite hjälp med sysadminmässigt).

En spindling brukar innebära att jag laddar ner alla siter dom en ilsta jag har (ett jobb kan ha allt från 1000 URLer till 30 miljoner). Då ska jag på ett effektivt sätt ladda ner så många som möjligt parallellt (maskiner som spindlar kan ha 1-X CPUer och olika mängd minne), komprimera dem och sen lägga dom i en protobuf på disk för bearbetning (ta ut den datan jag vill ha).

Detta är för mitt projekt http://DNSDigger.com