Tag Archives: Javascript V8

starmap

TaTa …
2nd Athmosphere, ein Geschicklichkeits- und Gedächnistrainings-Spiel ist fertig geworden.
Tatsächlich wird es 2nd Athmosphere als iPad-Game im iTunes-Store geben, sobald Apple es durch gewunken hat, und eine html5 Versionmit etwas eingeschränkten Features. Auf dem iPad gibt’s später noch mehr Umgebungsgrafik und eine Hall of Fame (online eventuell im Apple Game-Center).

Es fehlt noch eine abschließende Komprimierung aber im Wesentlichen steht die Demo.

Und aus 2nd Athosphere hier die Routine, die hübsche zufällige Sternenkarten auf einem canvas-Element erzeugt:



// prepare starmap in an existing HTML-DIV; Name-> starMapParentDOMElement
function starMap(){
  var width = window.innerWidth;
  var height = parseInt(window.innerHeight);
  var colr = function(){return parseInt( 255-Math.random()*70);};
  var grad = function(winkel){return (winkel * Math.PI / 180);};
  var nStars = function(){return parseInt(100 + Math.random()*500);};
  var cv = document.createElement('canvas');
  cv.setAttribute('width',width+'px');
  cv.setAttribute('height',height+'px');
  cv.style.position = "absolute";
  cv.style.top = "0px";
  cv.style.left = "0px";
  document.getElementById(starMapParentDOMElement).appendChild(cv);
  var ctxx = cv.getContext('2d');
  
  // darkblue background
  ctxx.fillStyle = "rgba(10,10,30,1.0)"; 
  ctxx.fillRect(0,0,width,height);
  ctxx.fill();
 
  for(var i=nStars();i;i-=1){
    // Stars
    ctxx.fillStyle = "rgba("+[colr(),colr(),colr()].join(',')+",0.8)";
    ctxx.beginPath();
    var x = Math.random()*width;
    var y = Math.random()*height;
    var r = 0.1+2.5*Math.random();
    ctxx.arc(x,y,((r>1.7)?r:0.5),0,grad(360),false);
    ctxx.closePath();
    ctxx.fill();
    // Nebel & Fog
    ctxx.fillStyle = "rgba("+[colr(),colr(),colr()].join(',')+",0.008)";
    ctxx.beginPath();
    x = Math.random()*width;
    y = Math.random()*height;
    r = 40 + 70* Math.random();
    ctxx.arc(x,y,r,grad(Math.random()*360),grad(180+Math.random()*180),false);
    ctxx.closePath();
    ctxx.fill();
  }
}

nStars beeinflusst die Zahl der Sterne.
In den Zeilen

var r = 0.1+2.5*Math.random();
und
ctxx.arc(x,y,((r>1.7)?r:0.5),0,grad(360),false);
wird auf das Erscheinungsbild der Sterne Einfluss genommen.
r = 40 + 70* Math.random();
ctxx.arc(x,y,r,grad(Math.random()*360),grad(180+Math.random()*180),false);

wirken auf die Nebel.

Und heraus kommen feine fenstergrosse Sternenkarten.

Die Kreise und gelben Strings sind natürlich nicht Teil der Sternenkarte sondern gehören zum Spiel.

_underscore.js

Eine interessante Javascript Utility-Sammlung für alle Arten von (seriellen) Objekten ist die _underscore.js von documentcloud (zu finden unter http://underscore.js.

Eine ganze Reihe von Funktionen für die Objekt-Manipulationen, die in anderen Sprachen zur Verfügung stehen, fehlen in Javascript. _underscore.js erweitert das Funktions-Angebot und stellt über 60 Utilities zur Verfügung.

Die Bibliothek nutzt dabei die nativen Funktionen aus ECMAScipt 5 soweit bereits verfügbar.

Weitere Funktionen können mit Hilfe der Erweiterungsfunktion _.mixin in die library zur Laufzeit hinzugeladen werden. Die folgenden Funktionen können so ’nachgeladen‘ werden:

sum: sum of numerical object elements
mean: aritmethic mean of numerical object elements
median: median (center element) of a sorted object
nrange: enhanced range function returning an array of the specified range

Um die Library zu nutzen, ist erst underscript mit <script src=“ ….. /underscript.js“ ><script> zu laden und dann das Addon mit den neuen Funktionen <script src=“ ….. /underscriptAddon.js“ ><script> darüber zu laden. die functioen stehen dann mit underscore mixin Syntax z.B. _([1,3,2,4,1]).sum() zur Verfügung.

Das mixim Plugin ist im Wiki (Stichwort mixin-Plugin catalog) gelinkt oder kann bei github herunter geladen werden: https://gist.github.com/1670507

speed Comparison: File IO von einfachen Objekten mit python 2.7 vs. node.js

Ich habe bisher fast alles mit Python lösen können. Dennoch konnte gerade beim Arbeiten mit Objekten, die viele Elemente beherbergen (z.B. der iExam-Fragenpool) eine hohe Performance nur mit Tricks wie multi-threading und subprocessing zum Verteilen auf die verschiedenen Prozessoren erreicht werden und selbst dann hatte ich immer den Eindruck, dass die Serialisierung mit cPickle etwas bremste.

node.js hat mich in ersten Tests mit erstaunlicher Performanz überrascht und ich habe mich gefragt, wie es sich im Umgang mit Objekten im direkten Vergleich schlagen wird.

Erst einmal mussten ein paar Zeilen Code her, um die beiden Kontrahenten fair vergleichen zu können.


#! /usr/bin/python
# python code
# start with >> python2.7 testFileIO.py
import os, sys
import random
import cPickle
import time

datapth = '/Users/usrName/Desktop/nodeWork/Testdaten'
outpth = '/Users/usrName/Desktop/nodeWork/testErgPy'

# prepare & save Testdaten 
with file(datapth,'wb') as outFle:
  print >> outFle, ''.join( map(chr, [random.randint(0,255) for i in xrange(150)]) )

ergs = dict()
for i in xrange(10000):
  ergs['%05i'%i] = '000000'

# Zeitmessung starten

sTM = int(time.time()*1000)
ssTM = sTM

for i in xrange(10000):
  r = file(datapth)
  erg = r.read()
  tm = int(time.time()*1000)
  ergs['%05i'%i] = tm-sTM
  with file(outpth,'wb') as ofle:
    cPickle.dump(ergs,ofle)
  ergs = cPickle.load(file(outpth))
  sTM = tm

print 'python needed: %s ms'%(tm-ssTM)

Durch die Vorbelegung der Dictionary-Elemente bleibt der IO-Aufwand über die Aufgabe weitgehend gleich. Da die tatsächliche Zeitdifferenz im ergs-Objekt abgelegt ist, kann das auch grafisch belegt werden.
Wie man sieht, beherbergt der Pythoncode keine Tricks (s.o) – um den direkten Vergleich mit Node.js zu erreichen, das ja bekanntlich in einer Schleife auf einem Prozessor läuft.

Unten steht die selbe Routine in coffeescript. Die intFormat(zahl, zeros) erzeugt eine Anmutung der Integerdarstellung im Formatstring bei Python ‚%05i’%i


#! /usr/local/bin/coffee
# coffeescript code auf node.js v0.6.7
# start with >> coffee testFileIO.coffee 

fs = require 'fs'

cntr = 0
fle = ''
datapth = '/Users/usrName/Desktop/nodeWork/Testdaten'
outpath = "/Users/usrName/Desktop/nodeWork/testErg"
ergs = {}

intFormat = (zahl,zeros) ->
  zahl = ''+zahl
  prefx = ''
  len = zahl.length
  for i in [0...(zeros-len)]
    prefx += "0"
  prefx+zahl
  
for i in [0...10000]
  ergs[intFormat(i,5)] = '000000'

# Zeitmessung starten

altTM = new Date()
altTM = altTM.getTime()
ssTM = altTM

for i in [0...10000]
  erg = fs.readFileSync datapth,encoding='utf-8'
  tm = new Date()
  tm = tm.getTime()
  ergs[intFormat(i,5)] = tm - altTM
  fs.writeFileSync outpath,JSON.stringify(ergs) 
  altTM = tm

console.log "node.js time gone: #{ tm-ssTM } ms"

Die Aufgabe für beide bestand also darin, in einer Schleife zehntausendmal ein dictionary Object mit 10.000 Einheiten aus einem File zu laden, ein Element zu ändern (float hineinschreiben), das dictionary zu serialisieren und wieder abzulegen.

Und hier ist das Ergebnis (gemittelt aus 10 Durchläufen):

Das File, das Python bei der Serialisierung mit cPickle anlegt (39.000 Zeichen/ 319kb), ist 3x größer als die JSON-Datei, die Node erzeugt (20.000 Zeichen/ 100kb). Das kann die unterschiedliche Performanz zum Teil erklären. Aber die Aufgabe war ja gerade, ein großes Objekt frequent zu laden und zu manipulieren – genau hier zeigte sich die V8javacript engine von node.js deutlich im Vorteil.

Fazit:
Node.js war im Mittel praktisch 5.37 mal schneller als Python (MacPro 3,1 Xeon (8x, 2.8 GHz)).

update on MacBook Pro (2.26 GHz Core2Duo): node.js 5.06 mal schneller als Python 2.7.2