tag:blogger.com,1999:blog-27072732302162611852024-09-02T01:18:53.464-07:00pythonjsraptorhttp://www.blogger.com/profile/14287416587600419675[email protected]Blogger18125tag:blogger.com,1999:blog-2707273230216261185.post-30447988121273784052015-07-22T18:11:00.001-07:002015-07-22T18:11:12.391-07:00Rusthon and WebWorkers<div dir="ltr" style="text-align: left;" trbidi="on">
<br /></div>
<p>
<a href="https://github.com/rusthon/Rusthon">Rusthon</a>
is the fork of PythonJS that I currently maintain and use on all my personal and work projects.
It has an improved JavaScript transpiler, with a powerful syntax that mixes Python and Golang.
Recently I added special syntax for timed processing and webworkers, see these posts:
<a href="http://rusthon-lang.blogspot.com/2015/07/javascript-backend-timeout-syntax.html">[1]</a>,
<a href="http://rusthon-lang.blogspot.com/2015/06/javascript-backend-webworkers.html">[2]</a>
</p>
<h3>WebWorkers</h3>
<p>
The WebWorker standard is many years old, but often web developers do not have time to break apart their code in order to use it. Code inside a webworker has no access to the DOM, and passing objects back and forth requires packing them into a message protocol. You also need to worry about loading your shared JavaScript with <b>importScripts</b>, or have some logic to create a URL Blob at runtime, and splitting off the worker code into its own file. In other words, refactoring your JavaScript to leverage webworkers, can be a big pain in the ass.
</p>
<p>
Rusthon has simple syntax inspired by Golang for using webworkers, see the wiki
<a href="https://github.com/rusthon/Rusthon/wiki/WebWorker-Syntax">here.</a>
The transpiler and runtime take care of all the details of passing messages, reconstructing objects, splitting apart your code, and generating a URL blob at runtime. Example <a href="https://github.com/rusthon/Rusthon/blob/master/examples/javascript_webworkers_classes.md">source code</a>.
</p>
<h3>transpiler input</h3>
<p>
This example passes instances of <b>SharedClass</b> back and forth from webworker to the main thread.
Python3 style function annotations are used to type the input arguments and return type,
this allows the transpiler to inject code to restore the objects <b>__proto__</b> class|prototype property,
this is required when you intend to call methods on objects that cross from webworker to main, or main to webworker.
</p>
<pre>
#backend:javascript
from runtime import *
def show(txt):
document.getElementById('CONTAINER').appendChild(
document.createTextNode(txt + '\n')
)
class SharedClass:
def __init__(self, x,y,z):
self.x = x
self.y = y
self.z = z
def foobar(self):
return self.x + self.y + self.z
with webworker:
def somefunction() -> SharedClass:
s = SharedClass(10,20,30)
return s
class MyWorker:
def send(self, obj:SharedClass ) -> SharedClass:
print obj
print obj.foobar()
obj.x = 10
return obj
def somemethod(self) -> SharedClass:
s = SharedClass(100,200,300)
return s
def main():
global WORKER
show('spawn worker...')
WORKER = spawn( MyWorker() )
show('creating SharedClass')
a = SharedClass(1,2,3)
print(a)
show(a.foobar())
show('sending data to worker')
WORKER <- a
show('getting data from worker')
b = <- WORKER
show(b.foobar())
c = <- somefunction()
show(c.foobar())
d = <- WORKER.somemethod()
show(d.foobar())
</pre>
<hr/>
<h3>javascript output - webworker</h3>
<p>
note below: <i>somefunction.returns = "SharedClass";</i> is the result of this input from above
<b>def somefunction() -> SharedClass:</b> that sets the return type of the function. The WebWorker runtime manager
checks the <b>returns</b> property of functions it calls, and sets the <b>__proto__</b> of the result in the main thread.
</p>
<pre>
var somefunction = function()
{
var s;
s = new SharedClass(10, 20, 30);
return s;
}
somefunction.returns = "SharedClass";
var MyWorker = function(){}
MyWorker.prototype.send = function(obj)
{
var obj;
obj.__proto__ = SharedClass.prototype;
console.log(obj);
console.log(obj.foobar());
obj.x = 10;
return obj;
}
MyWorker.prototype.send.returns = "SharedClass";
MyWorker.prototype.somemethod = function()
{
var s;
s = new SharedClass(100, 200, 300);
return s;
}
MyWorker.prototype.somemethod.returns = "SharedClass";
</pre>
<h3>javascript output - main</h3>
<pre>
var show = function(txt)
{
document.getElementById("CONTAINER").appendChild(document.createTextNode((txt + "\n")));
}
var SharedClass = function(x, y, z)
{
this.__init__(x, y, z);
}
SharedClass.prototype.__init__ = function(x, y, z)
{
this.x = x;
this.y = y;
this.z = z;
}
SharedClass.prototype.foobar = function()
{
return ((this.x + this.y) + this.z);
}
var main = function()
{
var a,c,b,d;
show("spawn worker...");
WORKER = __workerpool__.spawn({new:"MyWorker", args:[]});
show("creating SharedClass");
a = new SharedClass(1, 2, 3);
console.log(a);
show(a.foobar());
show("sending data to worker");
__workerpool__.send({message:a,id:WORKER})
show("getting data from worker");
__workerpool__.recv( WORKER, function (b) {
show(b.foobar());
__workerpool__.call( "somefunction", [], function (c) {
show(c.foobar());
__workerpool__.callmeth( WORKER, "somemethod", [], function (d) {
show(d.foobar());
});
});
});
}
</pre>
raptorhttp://www.blogger.com/profile/14287416587600419675[email protected]0tag:blogger.com,1999:blog-2707273230216261185.post-36479532048946326162015-05-12T12:51:00.002-07:002015-05-12T12:51:46.999-07:00Rapydscript Kicks Ass<div dir="ltr" style="text-align: left;" trbidi="on">
<br /></div>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBvjJC5H5oAh7FPa4F6lXPzsBi7QGCRJ7BLAmhHqQPwRaRvh6B11FbjSxOAbX1x0UPMDvqIt3SRTjXGgmn-g7aWpvFZgdeKpDlwANIOU_x6VVHSKUQiZ-b4cZa4fk_gf4pTzdk8fDkZLk/s1600/rs_logo_tiny.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBvjJC5H5oAh7FPa4F6lXPzsBi7QGCRJ7BLAmhHqQPwRaRvh6B11FbjSxOAbX1x0UPMDvqIt3SRTjXGgmn-g7aWpvFZgdeKpDlwANIOU_x6VVHSKUQiZ-b4cZa4fk_gf4pTzdk8fDkZLk/s320/rs_logo_tiny.png" /></a></div>
<p>
<a href="http://www.rapydscript.com/">Rapydscript</a> by <a href="">Alexander Tsepkov</a> is a Python to JavaScript translator that really kicks ass. It is stable, the transpiler can be run fully client side, produces very fast JavaScript, and is well maintained by Alex. Rapydscript syntax is very similar to PythonJS, and both can be used together in the same markdown file compiled by <a href="http://rusthon.github.io/Rusthon/">Rusthon</a>.
</p>
<p>
Rapydscript has the right mix of Pythonic-style and features to make it inter-operate well with JavaScript. Alex made all the right choices on what parts of Python to throw away, and adapting the syntax to the requirements imposed by generating fast JavaScript. Check out <a href="https://github.com/rusthon/Rusthon/blob/master/examples/hello_rapydscript.md">this</a> example for how to use Rapydscript in Rusthon.
</p>
raptorhttp://www.blogger.com/profile/14287416587600419675[email protected]0tag:blogger.com,1999:blog-2707273230216261185.post-54604838782188339542014-09-07T23:25:00.000-07:002014-09-07T23:25:21.526-07:00Python to Go<div dir="ltr" style="text-align: left;" trbidi="on">
<br /></div>
<p>
Golang is a fully typed language with simple and clean syntax.
The Go compiler will throw an error if you made a typo or called a method on
the wrong object. This means you need to worry less about runtime errors,
and writting unit tests. Go programs are compiled to native executables,
or can be compiled to JavaScript using <a href="https://github.com/gopherjs/gopherjs">GopherJS.</a>
</p>
<p>
PythonJS has a new backend in development that translates to Go. See the documentation <a href="https://github.com/PythonJS/PythonJS/blob/master/doc/go_syntax.md">here.</a> The Go backend supports translation of Python classes and list comprehensions to Go. The PythonJS syntax has also been extended to support Go features like: go-routines and channels.
</p>
<h3>Go/Python Meetup</h3>
<p>
The Barcelona Python users group is hosting a free meetup on Oct 13th, see the details <a href="http://www.meetup.com/python-185/events/204329322/">here</a>. I will be going and giving a talk about using PythonJS to translate to Go, and using GopherJS to translate it back to JavaScript.
</p>raptorhttp://www.blogger.com/profile/14287416587600419675[email protected]0tag:blogger.com,1999:blog-2707273230216261185.post-60451527540812424182014-07-22T21:09:00.000-07:002014-09-04T01:20:26.621-07:00new pythonjs syntax<div dir="ltr" style="text-align: left;" trbidi="on">
<br /></div>
<p>
PythonJS is being extended with optional static typing and new syntax.
The translator pre-processes input source code and transforms it into an intermediate form that can be parsed by Python's ast module. This simplifies adding new syntax to PythonJS, see this
<a href="https://github.com/PythonJS/PythonJS/commit/3f087983b4d0ea8048f7bc72355f2b9c0a81b159">commit</a> that implements Exception Expressions.
</p>
<pre>
a = d[ 'somekey' ] except KeyError: 'mydefault'
</pre>
<h3>inline anonymous functions</h3>
<p>
I am now researching new syntax that can be added to PythonJS.
After looking at <a href="https://github.com/atsepkov/RapydScript">RapydScript</a>, I see that inline anonymous functions are a must have, and recently implemented them in PythonJS.
Inline functions can be used in function calls as a named keyword argument,
or in a dict literal. This solves the problem that Lambda functions can only be a single statement,
which is often not that useful.
</p>
<pre>
a.func(
callback1=def (x,y,z):
x += y
return x - z,
callback2= def (x, y):
return x * y
)
b = {
'cb1' : def (x):
return x,
'cb2' : def (y):
return y
}
</pre>
<h3>switch</h3>
<pre>
switch a==b:
case True:
pass
case False:
pass
default:
pass
</pre>
<h3>Go channels and select</h3>
<pre>
def send_data( A:chan int, B:chan int, X:int, Y:int):
while True:
print('sending data..')
A <- X
B <- Y
def select_loop(A:chan int, B:chan int, W:chan int) -> int:
print('starting select loop')
y = 0
while True:
print('select loop:',y)
select:
case x = <- A:
y += x
W <- y
case x = <- B:
y += x
W <- y
print('end select loop', y)
return y
def main():
a = go.channel(int)
b = go.channel(int)
w = go.channel(int)
go(
select_loop(a,b, w)
)
go(
send_data(a,b, 5, 10)
)
z = 0
while z < 100:
z = <- w
print('main loop', z)
print('end test')
</pre>raptorhttp://www.blogger.com/profile/14287416587600419675[email protected]0tag:blogger.com,1999:blog-2707273230216261185.post-42856249134257328272014-07-17T01:34:00.000-07:002014-07-17T01:34:10.722-07:00WebGL CSS3D Hybrid part2<div dir="ltr" style="text-align: left;" trbidi="on">
<br /></div>
<p>
Despite WebGL having been around since 2011, you probably do not run into many websites with 3D. And when you do, its likely a fullscreen game or demo, not a typical website. Traditional web technologies do not mix well with WebGL. Libraries like <a href="http://www.voodoojs.com/">Voodoo.js</a> try to bridge this gap by allowing you to insert 3D objects inside a normal webpage. Voodoo.js graphics are not anti-aliased when rendering with WebGL, the contrast with the rest of the smooth text and graphics on a webpage then becomes very harsh and downright ugly.
</p>
<p>
<a href="https://github.com/PythonJS/PythonJS/blob/master/regtests/html/threepy.py">Threepy</a> is an experimental library built on THREE.js that allows <b>some</b> HTML and CSS to be mixed together with WebGL rendering and post-processing FX. The library wraps many standard HTML element types with special hacks like: callbacks, catching events, and rendering to proxy <i>clones</i>. Not every combination of HTML and CSS is compatible with this method. The video below tests the basic UI elements:
checkboxes, text input, select drop down lists, number input, color selector, tab menus, slider controls, images and videos. Works with GoogleChrome and NodeWebkit.
</p>
<iframe width="560" height="315" src="//www.youtube.com/embed/USf52MdmjrI" frameborder="0" allowfullscreen></iframe>raptorhttp://www.blogger.com/profile/14287416587600419675[email protected]7tag:blogger.com,1999:blog-2707273230216261185.post-38769184838982302392014-07-07T22:09:00.001-07:002014-07-10T07:20:20.179-07:00WebGL CSS3D Hybrid<div dir="ltr" style="text-align: left;" trbidi="on">
<br /></div>
<p>
Jerome Etienne has an interesting post where he combines CSS3D and WebGL, see his post <a href="http://learningthreejs.com/blog/2013/04/30/closing-the-gap-between-html-and-webgl/">here.</a> However, his method is not compatible with Three.js post-processing shaders that is required to blur and perform other 2D effects on the 3D rendering.
</p>
<p>The videos below show integration of WebGL and CSS3D with post-processing in THREE.js. The main hack do to this requires double rendering the DOM in two CSS3D layers. The first layer is rendered under the WebGL layer, and is a clone of the top CSS layer.
The top CSS layer is rendered transparent over the WebGL layer and catches keyboard and mouse events. The WebGL layer is rendered with alpha blending. See the source code <a href="https://github.com/PythonJS/PythonJS/blob/master/regtests/html/webgl_css3d_simple_editor.html">here.</a>
</p>
<iframe width="420" height="315" src="//www.youtube.com/embed/TbBfsrDzHTU" frameborder="0" allowfullscreen></iframe>
<iframe width="420" height="315" src="//www.youtube.com/embed/Dc5SZUYMSjk" frameborder="0" allowfullscreen></iframe>
<iframe width="560" height="315" src="//www.youtube.com/embed/_EkwusD0WS4" frameborder="0" allowfullscreen></iframe>
<h3>dnd, iframes, video, collada</h3>
<p>
<b>Update july10th,</b> testing new hacks to integrate: iframes, html5 video, and collada 3D files by drag and drop.
Starting new module <a href="https://github.com/PythonJS/PythonJS/blob/master/regtests/html/dddom.py">dddom.py</a> with simple API for creating 3D widgets mixing WebGL and CSS3D.
</p>
<iframe width="560" height="315" src="//www.youtube.com/embed/pnBK5bH1I1w" frameborder="0" allowfullscreen></iframe>raptorhttp://www.blogger.com/profile/14287416587600419675[email protected]0tag:blogger.com,1999:blog-2707273230216261185.post-21067342819953789672014-06-24T18:24:00.000-07:002014-06-24T18:24:23.355-07:00GLSL Classes<div dir="ltr" style="text-align: left;" trbidi="on">
<br /></div>
<p>
GLSL is not object oriented, there are no classes or method calls. GLSL4.0 has <a href="https://www.opengl.org/registry/specs/ARB/shader_subroutine.txt">subroutine variables</a> that can provide an object oriented <a href="https://www.opengl.org/discussion_boards/showthread.php/182266-Do-GLSL-subroutines-cause-any-performance-overhead">solution</a>, but this is not compatible with GLSL in WebGL.
</p>
<h3>PythonJS GPU Class</h3>
<p>
In the example below an array of MyObject is created and uploaded to the GPU, where it is iterated over.
The method call <b>s.mymethod(1.1, 2.2)</b> translates to <b>MyObject_mymethod(s, 1.1, 2.2)</b> in the GLSL shader.
</p>
<pre>
@gpu.object
class MyObject:
@gpu.method
float def subroutine(self, x,y):
float x
float y
return x + y * self.attr2
@gpu.method
float def mymethod(self, x,y):
float x
float y
if self.index == 0:
return -20.5
elif self.index == 0:
return 0.6
else:
return self.subroutine(x,y) * self.attr1
def __init__(self, a, b, i):
self.attr1 = a
self.attr2 = b
self.index = int16(i)
class myclass:
def run(self, w):
self.array = [MyObject(1.1,1.2,x) for x in range(w)]
@returns( array=64 )
@gpu.main
def gpufunc():
struct* A = self.array
float b = 0.0
for s in iter(A):
b += s.mymethod(1.1, 2.2)
return b
return gpufunc()
</pre>raptorhttp://www.blogger.com/profile/14287416587600419675[email protected]2tag:blogger.com,1999:blog-2707273230216261185.post-77465056419490162014-06-22T21:01:00.001-07:002014-06-23T19:59:08.590-07:00GLSL Array of Arrays<div dir="ltr" style="text-align: left;" trbidi="on">
<br /></div>
<p>
WebGL shader code written in GLSL is based on the OpenGL-ES standard, see GLSL 1.2 <a href="http://www.opengl.org/registry/doc/GLSLangSpec.Full.1.20.8.pdf">spec pdf</a>.
GLSL 1.2 has no support for multidimensional arrays (array of arrays), and loops require a constant expression for iteration. These limitations make it very hard to write generic shader programs.
</p>
<p>
PythonJS shader translation provides a workaround, and supports one-level-deep array of arrays and iteration over them. The input array data and sizes can change at runtime because the shader is fully recompiled each call to its wrapper function. Attributes from the current scope in JavaScript can also be inlined into the shader. Read the syntax documentation <a href="https://github.com/PythonJS/PythonJS/blob/master/doc/gpu.md">here</a>.
</p>
<h3>array of array example</h3>
<pre>
class myclass:
def __init__(self, s):
self.s = s
def my_method(self):
return self.s
def run(self, w, h):
self.array = [ [x*y*0.5 for y in range(h)] for x in range(w) ]
@returns( array=64 )
@gpu.main
def gpufunc():
float* A = self.array
float b = self.my_method()
for subarray in A:
for j in range( len(self.array[0]) ):
b += subarray[j]
return b
return gpufunc()
</pre>
<h4>GLSL output</h4>
<p>
The inner function <b>gpufunc</b> becomes <b>main</b> below.
Inside gpufunc above, the assignment to <b>A</b> as a float pointer <b>float* A = self.array</b>
triggers the wrapper code to unroll <b>A</b> into <b>A_𝑛</b> and inline the values,
'𝑛' is the length of the array.
</p>
<pre>
void main() {
float A_0[4];
A_0[0]=0.0;A_0[1]=0.0;A_0[2]=0.0;A_0[3]=0.0;float A_1[4];A_1[0]=0.0;A_1[1]=0.5;A_1[2]=1.0;A_1[3]=1.5;float A_2[4];A_2[0]=0.0;A_2[1]=1.0;A_2[2]=2.0;A_2[3]=3.0;float A_3[4];A_3[0]=0.0;A_3[1]=1.5;A_3[2]=3.0;A_3[3]=4.5;float A_4[4];A_4[0]=0.0;A_4[1]=2.0;A_4[2]=4.0;A_4[3]=6.0;float A_5[4];A_5[0]=0.0;A_5[1]=2.5;A_5[2]=5.0;A_5[3]=7.5;float A_6[4];A_6[0]=0.0;A_6[1]=3.0;A_6[2]=6.0;A_6[3]=9.0;float A_7[4];A_7[0]=0.0;A_7[1]=3.5;A_7[2]=7.0;A_7[3]=10.5;
...
</pre>
<p>
the wrapper inlines the runtime value of <b>float b = self.my_method()</b>.
Iteration over the list <b>for subarray in A:</b> is translated into a for loop
that copies the data from <b>A_𝑛</b> into the iterator target <b>subarray</b>.
</p>
<pre>
float b;
b = 0.1;
for (int _iter=0; _iter < 4; _iter++) {
float subarray[4];
if (_iter==0) { for (int _J=0; _J<4; _J++) {subarray[_J] = A_0[_J];} }
if (_iter==1) { for (int _J=0; _J<4; _J++) {subarray[_J] = A_1[_J];} }
if (_iter==2) { for (int _J=0; _J<4; _J++) {subarray[_J] = A_2[_J];} }
if (_iter==3) { for (int _J=0; _J<4; _J++) {subarray[_J] = A_3[_J];} }
for (int j=0; j < 4; j++) {
b += subarray[j];
}
}
out_float = b;
}
</pre>
<h3>array of structs example</h3>
<p>
To iterate over an array of structs, wrap the struct* with <i>iter</i> in a for loop.
The struct below contains a float number 'num' and array of floats 'arr'.
The nested loop iterates over the indices of the structs array 'arr'.
</p>
<pre>
class myclass:
def new_struct(self, g):
return {
'num' : g,
'arr' : [0.1 for s in range(6)]
}
def run(self, w):
self.array = [ self.new_struct( x ) for x in range(w) ]
@returns( array=64 )
@gpu.main
def gpufunc():
struct* A = self.array
float b = 0.0
for s in iter(A):
b += s.num
for i in range(len(s.arr)):
b += s.arr[i]
return b
return gpufunc()
</pre>
<h4>GLSL output</h4>
<p>
The assignment <b>struct* A = self.array</b> triggers the wrapper code to generate a struct typedef
that is inserted into the shader header. self.array is inlined at runtime as <b>𝙎𝙩𝙧𝙪𝙘𝙩𝙉𝙖𝙢𝙚 A_𝑛</b>
Before the struct is constructed the array attribute <b>arr</b> is assigned to the variable <b>_arrA_𝑛</b>.
The for loop switches the iterator target <b>s</b> based on the loop index 𝑛.
</p>
<pre>
void main( ) {
float b;
b=0.0;
float _arrA_0[6];_arrA_0[0]=0.1;_arrA_0[1]=0.1;_arrA_0[2]=0.1;_arrA_0[3]=0.1;_arrA_0[4]=0.1;_arrA_0[5]=0.1;
𝙎𝙩𝙧𝙪𝙘𝙩𝙉𝙖𝙢𝙚 A_0 = 𝙎𝙩𝙧𝙪𝙘𝙩𝙉𝙖𝙢𝙚(0.0,_arrA_0);
...
𝙎𝙩𝙧𝙪𝙘𝙩𝙉𝙖𝙢𝙚 A_6 = 𝙎𝙩𝙧𝙪𝙘𝙩𝙉𝙖𝙢𝙚(6.0,_arrA_6);
float _arrA_7[6];_arrA_7[0]=0.1;_arrA_7[1]=0.1;_arrA_7[2]=0.1;_arrA_7[3]=0.1;_arrA_7[4]=0.1;_arrA_7[5]=0.1;
𝙎𝙩𝙧𝙪𝙘𝙩𝙉𝙖𝙢𝙚 A_7 = 𝙎𝙩𝙧𝙪𝙘𝙩𝙉𝙖𝙢𝙚(7.0,_arrA_7);
for (int _iter=0; _iter < 8; _iter++) {
𝙎𝙩𝙧𝙪𝙘𝙩𝙉𝙖𝙢𝙚 s;
if (_iter==0) { s=A_0;}
if (_iter==1) { s=A_1;}
if (_iter==2) { s=A_2;}
if (_iter==3) { s=A_3;}
if (_iter==4) { s=A_4;}
if (_iter==5) { s=A_5;}
if (_iter==6) { s=A_6;}
if (_iter==7) { s=A_7;}
b += s.num;
for (int i=0; i < 6; i++) {
b += s.arr[i];
}
}
out_float = b;
}
</pre>
raptorhttp://www.blogger.com/profile/14287416587600419675[email protected]0tag:blogger.com,1999:blog-2707273230216261185.post-34834956732817416292014-06-18T01:02:00.000-07:002014-06-18T01:06:30.515-07:00PythonJS GPU Mandelbrot<div dir="ltr" style="text-align: left;" trbidi="on">
<br /></div>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiN1AwLpZwCM55iC2rxutUvWqVtVk_whunSlmY1i2l40GsSj79z0oiROchD2a-kQNGrj2m7o1ur6S06IU0legNXhlCUdgbSlLcdlHktom60uk6UJaUStJ-8rJi-yF8e2NXUtr2UhZorAms/s1600/mandelbrot.py.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiN1AwLpZwCM55iC2rxutUvWqVtVk_whunSlmY1i2l40GsSj79z0oiROchD2a-kQNGrj2m7o1ur6S06IU0legNXhlCUdgbSlLcdlHktom60uk6UJaUStJ-8rJi-yF8e2NXUtr2UhZorAms/s400/mandelbrot.py.png" /></a>
<p>
PythonJS now supports translation of a limited subset of Python syntax into GPU code. This is done with a new GLSL backend using the <a href="https://github.com/3DRoberto/webclgl">WebCLGL</a> library by Roberto Gonzalez. The above benchmark calculates the Mandelbrot set for a size of 512x512, CPython3 with NumPy takes over eight seconds to complete, PythonJS specialized version takes just 0.2 seconds.
</p>
<h4><a href="https://github.com/PythonJS/PythonJS/blob/master/regtests/bench/mandelbrot.py">source code: mandelbrot.py</a></h4>
<p>
40X faster is probably not the best that WebCLGL can do, this benchmark was performed with a low-end GPU. To run the benchmarks yourself, install Python2 and Python3, and extract the latest PyPy to your home directory, and install NumPy for each. Install the NodeWebkit <a href="https://www.npmjs.org/package/nodewebkit">NPM package</a>. Then run these commands, and it will save the file <i>/tmp/mandelbrot.py.eps</i>:
</p>
<pre>
cd
git clone https://github.com/3DRoberto/webclgl.git
git clone https://github.com/PythonJS/PythonJS.git
cd PythonJS/regtests
./run ./bench/mandelbrot.py
</pre>raptorhttp://www.blogger.com/profile/14287416587600419675[email protected]0tag:blogger.com,1999:blog-2707273230216261185.post-61944558261094096552014-06-13T21:30:00.002-07:002014-06-13T21:30:47.739-07:00PythonJS SIMD Vectors part2<div dir="ltr" style="text-align: left;" trbidi="on">
<br /></div>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsaa3F16npko5eX7rnlqys1YUFqQmOgc_GZmIz69olwR0cO5z7C6maqF5dMObF9uRK7PpVUvYXc9Qn9pegXDj1LJNwNW9vd9Ud83XmeCaGJj-K23f-AplsLdOoVq8h3qqooCG9BztBDZk/s1600/simd_float32vec.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsaa3F16npko5eX7rnlqys1YUFqQmOgc_GZmIz69olwR0cO5z7C6maqF5dMObF9uRK7PpVUvYXc9Qn9pegXDj1LJNwNW9vd9Ud83XmeCaGJj-K23f-AplsLdOoVq8h3qqooCG9BztBDZk/s400/simd_float32vec.png" /></a>
<p>
The Dart backend has a new class <b>float32vec</b> that encapsulates a list of <a href="http://api.dartlang.org/dart_typed_data/Float32x4.html">Float32x4</a> SIMD vectors. The class acts like a normal vector allowing you to do element wise operations and look-ups, while under-the-hood it will index and operate on the appropriate sub-vector. This allows you to write SIMD accelerated code and not have to manually break things apart into chunks of four. Looping over the sub-vectors and encapsulation adds some overhead and slows down performance for arrays with more than 32 elements. The micro benchmark above was performed with 32 elements and shows better performance than CPython with NumPy.
</p>
<p>
<b>
<a href="https://github.com/PythonJS/PythonJS/blob/master/regtests/bench/simd_float32vec.py">benchmark source code</a>
</b>
</p>
<hr/>
<h3>float32vec</h3>
<pre>
class float32vec:
def __init__(self, items):
self[...] = new( List() )
self.length = items.length
i = 0; s = 0
while i < items.length:
x = items[i]
y = items[i+1]
z = items[i+2]
w = items[i+3]
vec = new( Float32x4(x,y,z,w) )
self[...].add( vec )
i += 4
def __getitem__(self, index):
if index < 0: index = self.length + index
float32x4 vec = self[...][ index // 4 ]
lane = index % 4
if lane == 0: return vec.x
elif lane == 1: return vec.y
elif lane == 2: return vec.z
elif lane == 3: return vec.w
def __setitem__(self, index, value):
if index < 0: index = self.length + index
vec = self[...][ index // 4 ]
lane = index % 4
if lane == 0: vec = vec.withX(value)
elif lane == 1: vec = vec.withY(value)
elif lane == 2: vec = vec.withZ(value)
elif lane == 3: vec = vec.withW(value)
self[...][ index // 4 ] = vec
def __add__(self, other):
arr = new( List() )
for i, vec1 in enumerate( self[...] ):
vec2 = other[...][ i ]
arr.add( vec1+vec2 )
v = inline("new float32vec([])")
v.length = self.length
v[...] = arr
return v
def __mul__(self, other):
arr = new( List() )
for i, vec1 in enumerate( self[...] ):
vec2 = other[...][ i ]
arr.add( vec1*vec2 )
v = inline("new float32vec([])")
v.length = self.length
v[...] = arr
return v
</pre>raptorhttp://www.blogger.com/profile/14287416587600419675[email protected]0tag:blogger.com,1999:blog-2707273230216261185.post-62744811195007529152014-06-13T04:59:00.000-07:002014-06-13T04:59:39.236-07:00PythonJS SIMD Vectors<div dir="ltr" style="text-align: left;" trbidi="on">
<br /></div>
<p>
PythonJS using <i>direct</i> SIMD via the Dart backend and running in the Dart VM is about 6X faster than CPython with Numpy in the following micro benchmark testing float32x4 multiplication. SIMD stands for <i>single instruction multiple data</i>, and it allows you to instruct the CPU to perform the same math operation on a vector of data to increase performance. Read more about SIMD on my old research blog, <a href="http://pyppet.blogspot.com/2012/04/rpython-to-llvm-part2.html">here.</a>
</p>
<p>
I was expecting NumPy would have specialized the case of an array with four float32 elements to use SIMD. Searching around for why this is the case in NumPy, I could not find any clear answers why: <a href="https://groups.google.com/forum/#!topic/numpy/bpGVj8zNNWQ">[1]</a>,
<a href="http://numpy-discussion.10968.n7.nabble.com/Byte-aligned-arrays-td3887.html">[2]</a>. More confused and curious, I jumped into the PyPy IRC chat room, and Matti Picus gave me the answer: NumPy has no direct support for SIMD, instead it relies on helper libraries like: MKL, <a href="http://www.netlib.org/blas/">BLAS</a>, and lapack.
</p>
<p>
The DartVM includes SIMD and float32x4 and int32x4 primities as part of the core language, you simply import <a href="https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/dart:typed_data"><b>dart:typed_data</b></a>. Google Chrome and FireFox are also in the process of supporting SIMD.
</p>
<h3>SIMD multiply micro benchmark</h3>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgad4TbXlmWjl1yJ51GxIJ1idFy8KDhM-HcikVjokUpTmpjaMyUlW1lG0dK4o8WN8YSie2h7E6g7K5ctL0qIJGo4M4zPxF-TMlrN1T_3gWzncZIIbbGHk59KuGSq5nLKx9dkV3fgEEGQPA/s1600/simd_float32x4.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgad4TbXlmWjl1yJ51GxIJ1idFy8KDhM-HcikVjokUpTmpjaMyUlW1lG0dK4o8WN8YSie2h7E6g7K5ctL0qIJGo4M4zPxF-TMlrN1T_3gWzncZIIbbGHk59KuGSq5nLKx9dkV3fgEEGQPA/s400/simd_float32x4.png" /></a>
<p>
The PythonJS translator has been updated to pass type information to the Dart backend, and translate <b>numpy.array</b> into a Float32x4 vector if it has been typed as <i>float32x4</i>. See my previous blog post about optional static typing, <a href="http://pythonjs.blogspot.com/2014/06/optional-static-typing.html">here</a>.
</p>
<pre>
def main():
start = time()
float32x4 a = numpy.array(
[1.0001, 1.0002, 1.0003, 1.0004],
dtype=numpy.float32 )
float32x4 b = numpy.array(
[1.00009, 1.00008, 1.00007, 1.00006],
dtype=numpy.float32 )
float32x4 c = numpy.array(
[1.00005, 1.00004, 1.00003, 1.00002],
dtype=numpy.float32 )
arr = []
for i in range(20000):
c *= a*b
arr.append( a*b*c )
print(time()-start)
</pre>raptorhttp://www.blogger.com/profile/14287416587600419675[email protected]0tag:blogger.com,1999:blog-2707273230216261185.post-31966000137644092642014-06-11T20:43:00.000-07:002014-12-23T11:36:41.152-08:00PythonJS faster than CPython part2<div dir="ltr" style="text-align: left;" trbidi="on">
<br /></div>
<p>
My earlier post <a href="http://pythonjs.blogspot.com/2014/05/pythonjs-now-faster-than-cpython.html">PythonJS now faster than CPython</a> struck a nerve with the Python community, and some heated debate on <a href="https://news.ycombinator.com/item?id=7865434">Hacker News</a>. The fact is that CPython is embarrassingly slow compared to V8, and the adoption rate of Python3 is <a href="http://alexgaynor.net/2013/dec/30/about-python-3/">very slow</a> compared to JavaScript's <a href="http://readwrite.com/2013/08/09/why-javascript-will-become-the-dominant-programming-language-of-the-enterprise">explosive growth</a>.
</p>
<p>
As pointed out by a few people in Hacker News thread, my first benchmarks were performed with PyPy1.9, so I have updated the test runner to use the latest PyPy 2.3.1 and PyPy1.9. I have also removed the micro-benchmarks, and now only include benchmarks from the Unladen Swallow <a href="http://code.google.com/p/unladen-swallow/source/browse/tests/">test suite</a>.
</p>
<p>
PythonJS (with the fast-backend) is faster than CPython in four of the following five benchmarks. Some may argue that this is not a fair comparison because the fast-backend is only a subset of the Python language standard. Keep in mind that: 1. it is large and useful subset, and 2. PythonJS is designed to allow you to mix both modes with in the same script by blocking out code as <i>fully compliant</i> or <i>fast</i> using special <b>with</b> blocks or calling <b>pythonjs.configure</b>.
</p>
<h3>nbody</h3>
<p>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhs7cSCpJwwTjJdB7u8u3E4iAzPqfBZ3h92FfQ9xN_rrNYh2jWkxZXJZxbowiIC01uswQNnIWXRFtVcQFMqU6aw7wLGo76fct3MMJHtkCjFd0p2XqORVl_cAKCwiOZSgG9rgI2OSmBfj58/s1600/nbody.py.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhs7cSCpJwwTjJdB7u8u3E4iAzPqfBZ3h92FfQ9xN_rrNYh2jWkxZXJZxbowiIC01uswQNnIWXRFtVcQFMqU6aw7wLGo76fct3MMJHtkCjFd0p2XqORVl_cAKCwiOZSgG9rgI2OSmBfj58/s400/nbody.py.png" /></a>
<p/>
<h3>pystone</h3>
<p>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEildgiQcQIHHQV4ZHtVzPJlRVb6pR3s1XhDezOQvaplHj5QL3fdk34PWDqr2H2pbeqZfGVC7EybCS1vuXQdEswSnB3GEClnwDHIjFsVn2tlYwW6kf_HtP70D4OCQ1gd5GEAGSWiev6VRno/s1600/pystone.py.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEildgiQcQIHHQV4ZHtVzPJlRVb6pR3s1XhDezOQvaplHj5QL3fdk34PWDqr2H2pbeqZfGVC7EybCS1vuXQdEswSnB3GEClnwDHIjFsVn2tlYwW6kf_HtP70D4OCQ1gd5GEAGSWiev6VRno/s400/pystone.py.png" /></a>
<p/>
<h3>richards</h3>
<p>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj43Evpb_WSKNY3QlU9lopCLEplHpDT7jPQv1q5Tysj0-WxCsScJBryJWkaZK-2yDihK-Xx-KtvAG1fXCofoW-SRYNs31vGsdMW0g5_gGIdWVqXKWbxvwk1ZBtoiPNDNbNE9Cd57JstyQM/s1600/richards.py.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj43Evpb_WSKNY3QlU9lopCLEplHpDT7jPQv1q5Tysj0-WxCsScJBryJWkaZK-2yDihK-Xx-KtvAG1fXCofoW-SRYNs31vGsdMW0g5_gGIdWVqXKWbxvwk1ZBtoiPNDNbNE9Cd57JstyQM/s400/richards.py.png" /></a>
<p/>
<h3>fannkuch</h3>
<p>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsDfV-MLcqyn2CN4yYP5BUXNDvwhPYmNPT4SxgY6oS59xPaJvcCFQNihmmMM8e0ucHuc-MWjuXJrlg7sK3cR5u95j6BlFPq5kKh5Ckw3hWJdh8jtfl96xl2Fau_qXJ9d5R6olcIV96uuI/s1600/fannkuch.py.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsDfV-MLcqyn2CN4yYP5BUXNDvwhPYmNPT4SxgY6oS59xPaJvcCFQNihmmMM8e0ucHuc-MWjuXJrlg7sK3cR5u95j6BlFPq5kKh5Ckw3hWJdh8jtfl96xl2Fau_qXJ9d5R6olcIV96uuI/s400/fannkuch.py.png" /></a>
<p/>
<h3>float</h3>
<p>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0-7fcHmD3-oKffKHiThzh_mJmgCnxd6o2ZPWxFH2Sdo70aqDjos3psmNwgsAQzKH1iEhfaovkfiHuHPJ8PSvGw9eeXxzOzcPAc4E8ogXKeTWk0i8DIXmtOEEhrZ1R8usqj5fx3OZ-NAc/s1600/float.py.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0-7fcHmD3-oKffKHiThzh_mJmgCnxd6o2ZPWxFH2Sdo70aqDjos3psmNwgsAQzKH1iEhfaovkfiHuHPJ8PSvGw9eeXxzOzcPAc4E8ogXKeTWk0i8DIXmtOEEhrZ1R8usqj5fx3OZ-NAc/s400/float.py.png" /></a>
</p>
<p>
<a href="https://github.com/PythonJS/PythonJS/tree/master/regtests/bench">benchmark source code</a>
</p>
<hr/>
<p>
Python has some big problems not just speed, like running on mobile devices. Translation to JavaScript, and other targets like: C++ and Rust, make it possible to side step the Python interpreter and that makes deployment much simpler.
</p>
raptorhttp://www.blogger.com/profile/14287416587600419675[email protected]0tag:blogger.com,1999:blog-2707273230216261185.post-9441605286540181182014-06-07T00:23:00.000-07:002014-06-07T00:23:28.780-07:0064bit integer long type<div dir="ltr" style="text-align: left;" trbidi="on">
<br /></div>
<p>
PythonJS now has a new static type <b>long</b> that can be used to mark a variable as a 64bit integer, see this <a href="https://github.com/PythonJS/PythonJS/commit/d534822bff0512374d749af7418335da536e1e7d">commit</a>. JavaScript has no native support for native 64bit integers, so the translator will use the <a href="https://github.com/dcodeIO/Long.js">Long.js API</a> to construct a <i>Long</i> object and call the appropriate methods for math and comparison logic.
</p>
<h4>python input</h4>
<pre>
def main():
long x = 65536
long y = x * x
long z = 4294967296
TestError( y==z )
long a = z + z
long b = 8589934592
TestError( a==b )
TestError( y < b )
TestError( b > y )
TestError( y <= b )
TestError( b >= y )
</pre>
<h4>javascript output</h4>
<pre>
main = function() {
if (__NODEJS__==true) var long = require('long');
x = long.fromString("65536");
y = x.multiply(x);
z = long.fromString("4294967296");
TestError( y.equals(z) );
a = z.add(z);
b = long.fromString("8589934592");
TestError( a.equals(b) );
TestError( y.lessThan(b) );
TestError( b.greaterThan(y) );
TestError( y.lessThanOrEqual(b) );
TestError( b.greaterThanOrEqual(y) );
}
</pre>
raptorhttp://www.blogger.com/profile/14287416587600419675[email protected]0tag:blogger.com,1999:blog-2707273230216261185.post-62399332762561124202014-06-06T09:31:00.000-07:002014-06-07T00:25:47.638-07:00optional static typing<div dir="ltr" style="text-align: left;" trbidi="on">
<br /></div>
<p>
People have been asking for optional types for Python for at least <a href="http://www.artima.com/weblogs/viewpost.jsp?thread=85551">10 years</a>, and only recently have a couple of good solutions appeared, one is MyPy by Jukka Lehtosalo, but the <a href="https://github.com/JukkaL/mypy">github project</a> hasn't been updated in several months, and no recent updates on the <a href="http://mypy-lang.blogspot.co.uk/">dev blog</a> either. Python could greatly benefit from optional typing, it makes your code more clear and readable, can provide better compile or time checks, and better performance.
</p>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXgLPYenB3hhGQYZF756axxSjTFpxafcBfJJnN_dPHMdgR61GdzFbnGVaqb_JDpdhNUN_UXX-1hlOylApdl3-UceWazgs6fVRKSd2Bi8ekTfGaZ-95r8oRbBLTamNwbIPr2p_mKoj3aSI/s1600/typed_int_and_list.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXgLPYenB3hhGQYZF756axxSjTFpxafcBfJJnN_dPHMdgR61GdzFbnGVaqb_JDpdhNUN_UXX-1hlOylApdl3-UceWazgs6fVRKSd2Bi8ekTfGaZ-95r8oRbBLTamNwbIPr2p_mKoj3aSI/s400/typed_int_and_list.png" /></a>
<h5><a href="https://github.com/PythonJS/PythonJS/blob/master/regtests/bench/typed_int.py">typed_int.py</a></h5>
<p>
The above benchmark shows PythonJS in normal mode with statically typed variables is 20 times faster compared to below without statically typed variables.
</p>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQWju0h95HZbvtgwRLvDzVdphTqzITfOjgqAOv0o5B0Aj8901w6rVFyi0L-_DD3BwsxIhne8PGUoIIatWgNzM9Fm2LuHqTBxsCGhc6EA4EtiDnBIfYLVQppEEUVAqc7R3uStvYN4cYsEg/s1600/untyped_int_and_list.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQWju0h95HZbvtgwRLvDzVdphTqzITfOjgqAOv0o5B0Aj8901w6rVFyi0L-_DD3BwsxIhne8PGUoIIatWgNzM9Fm2LuHqTBxsCGhc6EA4EtiDnBIfYLVQppEEUVAqc7R3uStvYN4cYsEg/s400/untyped_int_and_list.png" /></a>
<h5><a href="https://github.com/PythonJS/PythonJS/blob/master/regtests/bench/untyped_int.py">untyped_int.py</a></h5>
<p>
Most of the performance gain comes from typing the <i>arr</i> variable as <b>list</b>, this allows the translator to bypass a runtime method lookup and instead directly call <i>arr.push</i>.
</p>
<h3>new syntax</h3>
<pre>
def f(arr, x):
list arr
int x
int y = somefunction()
arr.append( x+y )
</pre>
<p>
PythonJS allows you to type each variable in a function body as a plain statement <b>int x</b> or in an assignment expression <b>int z = somefunction()</b>. This is different from the approach of MyPy where things can only be typed in the <a href="http://blog.pirx.ru/media/files/2013/python-optional-typing/#17">function's annotations</a>. It is implemented as a simple text pre-processor, for the details see <a href="https://github.com/PythonJS/PythonJS/issues/104">here</a>, and source code <a href="https://github.com/PythonJS/PythonJS/blob/master/pythonjs/typedpython.py">here</a>. This is still a very new feature and can only optimize a few cases. In the future it can be leveraged to further increase performance, and provide translation-time error checking.
</p>
raptorhttp://www.blogger.com/profile/14287416587600419675[email protected]2tag:blogger.com,1999:blog-2707273230216261185.post-89891370654482243252014-06-05T09:05:00.001-07:002014-06-05T09:13:51.661-07:00automatic synchronous to async transform<div dir="ltr" style="text-align: left;" trbidi="on">
<br /></div>
<p>
Asynchronous programming in JavaScript can quickly become a mess of callbacks,
sometimes it is called <a href="http://lostechies.com/bradcarleton/2014/02/18/taming-callback-hell-in-node-js/">`callback hell`</a>. This hell gets worse when you need to
move some logic to WebWorkers and pass data back and forth. Your once simple
synchronous function must be rewritten into many callbacks that shuffle data
around using postMessage and onmessage, and trigger the next callback.
</p>
<p>
PythonJS allows you to code in a synchronous style, and when your code it translated
to JavaScript, it will also be transformed into async callbacks. You can call
the <b>sleep</b> function to stop a function for a set amount of time while
other things take place, the function will resume after the timeout.
</p>
<p>
These commits:
<a href="https://github.com/PythonJS/PythonJS/commit/ce83b1c425773ff4974b1ae72f740c42bf46152d">[1]</a>,
<a href="https://github.com/PythonJS/PythonJS/commit/c2378dde14adc476cd3cbc13fa8e7c7f5309cdee">[2]</a>,
<a href="https://github.com/PythonJS/PythonJS/commit/05b1a1a5f239dfb98fb3b80417be609cd52f96aa">[3]</a>,
allow the webworker to directly call functions in the main thread, passing it data as normal function arguments.
Under the hood, PythonJS will call postMessage with the function name and arguments.
In the main thread this triggers the requested function with the
result sent back to the worker.
The function in the worker <i>halts</i> until it gets
this response from the main thread. What ends up being alot of async code,
can be expressed in just a few lines of sync code.
</p>
<h3>python input</h3>
<pre>
import threading
from time import sleep
shared = []
def blocking_func(x,y):
shared.append( x )
shared.append( y )
return x+y
def async_func( a ):
shared.append( a )
def main():
w = threading.start_webworker( worker, [] )
sleep(1.0)
assert len(shared)==3
assert shared[0]==10
assert shared[1]==20
assert shared[2]==30
print('main exit')
## marks this block of code as within the webworker
with webworker:
def worker():
## blocks because the result is assigned to `v`
v = blocking_func( 10, 20 )
## non-blocking because result is not used
async_func( v )
self.terminate()
</pre>
<h3>javascript output - main</h3>
<pre>
shared = [];
blocking_func = function(x, y) {
shared.append(x);
shared.append(y);
var __left16, __right17;
__left16 = x;
__right17 = y;
return ((( typeof(__left16) ) == "number") ? (__left16 + __right17) : __add_op(__left16, __right17));
}
async_func = function(a) {
shared.append(a);
}
main = function() {
var w;
w = __start_new_thread(worker, []);
__run__ = true;
var __callback0 = function() {
__run__ = true;
var __callback1 = function() {
console.log("main exit");
}
if (__run__) {
setTimeout(__callback1, 1000.0);
} else {
if (__continue__) {
setTimeout(__callback2, 1000.0);
}
}
}
if (__run__) {
setTimeout(__callback0, 200.0);
} else {
if (__continue__) {
setTimeout(__callback1, 200.0);
}
}
}
worker = "/tmp/worker.js";
</pre>
<h3>javascript output - webworker</h3>
<pre>
onmessage = function(e) {
if (( e.data.type ) == "execute") {
worker.apply(self, e.data.args);
if (! (threading._blocking_callback)) {
self.postMessage({ "type":"terminate" });
}
} else {
if (( e.data.type ) == "append") {
__wargs__[e.data.argindex].push(e.data.value);
} else {
if (( e.data.type ) == "__setitem__") {
__wargs__[e.data.argindex][e.data.key] = e.data.value;
} else {
if (( e.data.type ) == "return_to_blocking_callback") {
threading._blocking_callback(e.data.result);
}
}
}
}
}
self.onmessage = onmessage;
worker = function() {
var v;
v = self.postMessage({
"type":"call",
"function":"blocking_func",
"args":[10, 20]
});
var __blocking = function(v) {
self.postMessage({
"type":"call",
"function":"async_func",
"args":[v]
});
self.postMessage({ "type":"terminate" });
threading._blocking_callback = null;
}
threading._blocking_callback = __blocking;
}
</pre>raptorhttp://www.blogger.com/profile/14287416587600419675[email protected]3tag:blogger.com,1999:blog-2707273230216261185.post-79331277864427513972014-06-04T20:41:00.001-07:002014-06-04T20:41:51.266-07:00PythonJS IDE<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgB_47Q-oVjP1PCymAPy4n06JrIm4UpmKvmp4wW913YM7NXnP7MLatlGhqMPI_cot9f2M9zLToSK60RORscnxG9AGgp6iPg_3F9cp4AnhyGI3oa8FYBesHWhDZrQH0Eu4cJ8WCOTNcbpoI/s1600/pypubjs-0.0.6.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgB_47Q-oVjP1PCymAPy4n06JrIm4UpmKvmp4wW913YM7NXnP7MLatlGhqMPI_cot9f2M9zLToSK60RORscnxG9AGgp6iPg_3F9cp4AnhyGI3oa8FYBesHWhDZrQH0Eu4cJ8WCOTNcbpoI/s400/pypubjs-0.0.6.png" /></a><div dir="ltr" style="text-align: left;" trbidi="on">
<br /></div>
<p>
Above Pypubjs running in <a href="https://www.npmjs.org/package/nodewebkit">NodeWebkit</a>, with project preview in the Android emulator and native HTML window. Pypubjs is simple example that shows how to write a desktop applications using PythonJS and NodeWebkit. Pypubjs is itself written almost entirely in Python and HTML. It integrates with the <a href="https://www.npmjs.org/package/python-js">python-js</a> NodeJS package to dynamically compile itself, and code you write in the editor.
</p>
<a href="https://github.com/PythonJS/pypubjs">https://github.com/PythonJS/pypubjs</a>raptorhttp://www.blogger.com/profile/14287416587600419675[email protected]0tag:blogger.com,1999:blog-2707273230216261185.post-10998609865754480152014-05-27T23:37:00.000-07:002014-05-27T23:37:44.997-07:00Escaping the GIL with WebWorkers<div dir="ltr" style="text-align: left;" trbidi="on">
<br /></div>
<p>
The Global Interpreter Lock (GIL) prevents threads in Python from using all cores for CPU bound tasks, and using more threads can even make your program slower. These limitations of the GIL can be bypassed with the faking <b>threading</b> module in PythonJS. The fake threading module provides a function <b>threading.start_webworker(f,args)</b> that will run the function <i>f</i> with <i>args</i> in a new WebWorker. If you pass a list or dict as arguments to the worker function they will become shared between the parent and worker process (each append operation on a list will call <i>self.postMessage</i> to keep the parent and child in sync).
</p>
<p>
The following benchmark measures how many prime numbers can be found per-second. These tests were done with a dual core CPU, NodeJS 0.10.22, and <a href="https://github.com/eugeneware/workerjs">workerjs</a>. The dual core version of the script is 2X faster than the single core version when translated by PythonJS.
</p>
<p>
<h3>prime numbers per-second (single core)</h3>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggZLHL4g5mCZxqJNV6fQowFePt_AHfhGea6poOa2zrv8G_P8OSs3LM_yRkSIKMoWTxs3FSySTGuDhTXfW_4ALReJPn4D_o_yrm51qryIuDYSZSX4opf2DTa9VONeaxSl9XvSzvVfHFaDk/s1600/primes-single-core.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggZLHL4g5mCZxqJNV6fQowFePt_AHfhGea6poOa2zrv8G_P8OSs3LM_yRkSIKMoWTxs3FSySTGuDhTXfW_4ALReJPn4D_o_yrm51qryIuDYSZSX4opf2DTa9VONeaxSl9XvSzvVfHFaDk/s400/primes-single-core.png" /></a>
<a href="https://github.com/PythonJS/PythonJS/blob/master/regtests/bench/webworker_single.py">https://github.com/PythonJS/PythonJS/blob/master/regtests/bench/webworker_single.py</a>
</p>
<p>
<h3>prime numbers per-second (dual core)</h3>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsiwnjsE6xwHh894T21NyqxupLrDG0mjZ5euuZsj2pqkWDNFN1bq4cZxNZLMu6n85AuwmbmXrKSyeSHK7G4CjfZCJVok9p-g8oaEXCSkky6-rWMWL4WPqRUu9ixJ3tV2gO55AkYi-iYfA/s1600/primes-dual-core.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsiwnjsE6xwHh894T21NyqxupLrDG0mjZ5euuZsj2pqkWDNFN1bq4cZxNZLMu6n85AuwmbmXrKSyeSHK7G4CjfZCJVok9p-g8oaEXCSkky6-rWMWL4WPqRUu9ixJ3tV2gO55AkYi-iYfA/s400/primes-dual-core.png" /></a>
<a href="https://github.com/PythonJS/PythonJS/blob/master/regtests/bench/webworker.py">https://github.com/PythonJS/PythonJS/blob/master/regtests/bench/webworker.py</a>
</p>
<hr/>
<h1>sleep(<i>T</i>)</h1>
<p>
If you looked at the source code for the benchmarks above you might have been surprised to see the <b>sleep</b> function imported from the <b>time</b> module. I recently added experimental support for <b>sleep</b> to PythonJS in these commits: <a href="https://github.com/PythonJS/PythonJS/commit/8f0b603703cb2c73940f420927e149b4b7485ae1">[1]</a>, <a href="https://github.com/PythonJS/PythonJS/commit/bdcc3b935251e8d9283a07e4d628f51c346101fe">[2]</a>. This allows you to write code in a simpler synchronous style, and behind the scenes the code will be broken down into blocks and async callbacks generated.
</p>
<h2>python input</h2>
<pre>
from time import sleep
def main():
sleep(0.01)
a = []
sleep(0.1)
a.append(1)
sleep(0.1)
a.append(2)
TestError( len(a)==2 )
</pre>
<h2>javascript output</h2>
<pre>
main = function() {
var a;
__run__ = true;
var __callback0 = function() {
a = [];
__run__ = true;
var __callback1 = function() {
a.append(1);
__run__ = true;
var __callback2 = function() {
a.append(2);
TestError("sleep.py",10,len(a)==2,"len(a)==2");
}
if (__run__) {
setTimeout(__callback2, 100.0);
} else {
if (__continue__) {
setTimeout(__callback3, 100.0);
}
}
}
if (__run__) {
setTimeout(__callback1, 100.0);
} else {
if (__continue__) {
setTimeout(__callback2, 100.0);
}
}
}
if (__run__) {
setTimeout(__callback0, 10.0);
} else {
if (__continue__) {
setTimeout(__callback1, 10.0);
}
}
}
</pre>raptorhttp://www.blogger.com/profile/14287416587600419675[email protected]0tag:blogger.com,1999:blog-2707273230216261185.post-9321096705478972752014-05-18T18:48:00.000-07:002014-05-18T18:48:05.565-07:00PythonJS now faster than CPython<div dir="ltr" style="text-align: left;" trbidi="on">
<br /></div>
<h3>pystone benchmark</h3>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9TWzsG7EMn9RGzT74M-oRvxdvq9enPFljmBDd5H3XU_U-Ja1TWG7h-1L8tyLOl6KGNAgqbSzRYnG6bV6Xd5EIJmGaTW1dQQydH0eebW2Ik_5tfSnE6xqKXn1fpxO57FYEvzjglfrgR7s/s1600/pystone.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9TWzsG7EMn9RGzT74M-oRvxdvq9enPFljmBDd5H3XU_U-Ja1TWG7h-1L8tyLOl6KGNAgqbSzRYnG6bV6Xd5EIJmGaTW1dQQydH0eebW2Ik_5tfSnE6xqKXn1fpxO57FYEvzjglfrgR7s/s400/pystone.png" /></a>
<p>
<b>
PythonJS using the dart backend is 6x faster than CPython.
</b>
</p>
<p><a href="https://github.com/PythonJS/PythonJS/blob/master/regtests/bench/pystone.py">pystone.py</a></p>
<h3>nbody benchmark</h3>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimBdNADFeJmVMCvvXkCcfe6d01yf_7Sc4QhrA0A0f64Mzk3kSQEh4l-TSea7O2j1c-zmR8bQcIvFV2xUPQVu0tSXXwm4ojeJJI-NM9YplcqS0DcVI5IzvIdf5iGQk5yZooVOAt6JLYA64/s1600/nbody.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimBdNADFeJmVMCvvXkCcfe6d01yf_7Sc4QhrA0A0f64Mzk3kSQEh4l-TSea7O2j1c-zmR8bQcIvFV2xUPQVu0tSXXwm4ojeJJI-NM9YplcqS0DcVI5IzvIdf5iGQk5yZooVOAt6JLYA64/s400/nbody.png" /></a>
<p>
<b>
PythonJS using the fast javascript backend is faster than CPython and even 2x faster than PyPy.
</b>
</p>
<p><a href="https://github.com/PythonJS/PythonJS/blob/master/regtests/bench/nbody.py">nbody.py</a></p>
<h3>richard's benchmark</h3>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEik2inxwQB2-am6Mo83Za-kOWrAEofrsBI1g6e1cphj1wcb08UIOPkRBOP-2TR4gQ4jSgJ-D5xdIR4ikg5Pt7zULKkh7EjVMHHXHOcWDYlMwbLFoDE_YROJeQ2lLEcbQHmel-cO0inO0bU/s1600/richards.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEik2inxwQB2-am6Mo83Za-kOWrAEofrsBI1g6e1cphj1wcb08UIOPkRBOP-2TR4gQ4jSgJ-D5xdIR4ikg5Pt7zULKkh7EjVMHHXHOcWDYlMwbLFoDE_YROJeQ2lLEcbQHmel-cO0inO0bU/s400/richards.png" /></a>
<p>
<b>
PythonJS using the dart backend is 7x faster than CPython.
</b>
</p>
<p><a href="https://github.com/PythonJS/PythonJS/blob/master/regtests/bench/richards.py">richards.py</a></p>
<h3>float benchmark</h3>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiv4fMRaswjGeVeH-LgU1Rq81eK7uJP9UBNsgYH5Iik48pzP0jtJx6E9eqHVB6CP0gTXvv_YAMLiA3w2kA37J65k8iTXzWRYCt4MlOEYvK7g9-JTcj-JvHdCwiE0PQyB1swy0830s50Mpw/s1600/float.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiv4fMRaswjGeVeH-LgU1Rq81eK7uJP9UBNsgYH5Iik48pzP0jtJx6E9eqHVB6CP0gTXvv_YAMLiA3w2kA37J65k8iTXzWRYCt4MlOEYvK7g9-JTcj-JvHdCwiE0PQyB1swy0830s50Mpw/s400/float.png" /></a>
<p>
<b>
PythonJS using the dart backend is 3x faster than CPython.
</b>
</p>
<p><a href="https://github.com/PythonJS/PythonJS/blob/master/regtests/bench/float.py">float.py</a></p>
<hr/>
<h2>Micro-Benchmarks</h2>
<h4>recursive fibonacci micro-benchmark</h4>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPPnoheBBzRVrU2DSa_et5UBeW7DsTRhnwDHI7wrkVvE4H6LAPjpievbM81ShUmNrvVI5SftNtL1YsERAU30LZ8pwDVaMDv3zMovdHEirYPH1AmL554VGB02GwxDV2zszL_7-Vl67jBBs/s1600/recursive_fib.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPPnoheBBzRVrU2DSa_et5UBeW7DsTRhnwDHI7wrkVvE4H6LAPjpievbM81ShUmNrvVI5SftNtL1YsERAU30LZ8pwDVaMDv3zMovdHEirYPH1AmL554VGB02GwxDV2zszL_7-Vl67jBBs/s400/recursive_fib.png" /></a>
<p>
<b>
PythonJS using the dart backend is 27x faster than CPython and 7x faster than PyPy.
</b>
</p>
<p><a href="https://github.com/PythonJS/PythonJS/blob/master/regtests/bench/recursive_fib.py">recursive_fib.py</a></p>
<h4>simple add loop micro-benchmark</h4>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgg1pNMTrVwXQrcNV-bi18P-6yEUKGbdHnGeMNTbenu9n_zoKAac33NfvxMy414LAsoNaZSwxoljBXlEzg1xIj_N3DglvYcQvRKRb22X8-Rg39ub2jvl5IWudjgrWwGLVOPEhTUUqO2Bok/s1600/add.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgg1pNMTrVwXQrcNV-bi18P-6yEUKGbdHnGeMNTbenu9n_zoKAac33NfvxMy414LAsoNaZSwxoljBXlEzg1xIj_N3DglvYcQvRKRb22X8-Rg39ub2jvl5IWudjgrWwGLVOPEhTUUqO2Bok/s400/add.png" /></a>
<p>
<b>
PythonJS using any backend, is about 30x faster than CPython.
</b>
</p>
<p><a href="https://github.com/PythonJS/PythonJS/blob/master/regtests/bench/add.py">add.py</a></p>
<hr/>
<p>
The benchmarks were run with node.js 0.10.22, pypy 1.9, and dart-sdk 1.0. To run them yourself: get the latest PythonJS source from <a href="https://github.com/PythonJS/PythonJS">github</a>, and download and extract the dart-sdk to ~/dart-sdk-1.0. The benchmark eps graphs are written to "/tmp"
</p>
<pre>
cd PythonJS/regtests
./run.py
</pre>
raptorhttp://www.blogger.com/profile/14287416587600419675[email protected]0