Comments (17)
Thank you. I have merged it to master.
I refactored the project to using prototypes (branch default). When performing a prof run of 3000000 Queues the summary looks like this:
prototyping
[Summary]:
ticks total nonlib name
182 18.8% 36.7% JavaScript
300 31.0% 60.5% C++
51 5.3% 10.3% GC
471 48.7% Shared libraries
14 1.4% Unaccounted
Your class based solution have the following summary when running the same number of queues:
classes
[Summary]:
ticks total nonlib name
2789 72.7% 85.3% JavaScript
427 11.1% 13.1% C++
236 6.1% 7.2% GC
568 14.8% Shared libraries
54 1.4% Unaccounted
from smqp.
I have actually started in the default branch. The performance gain is immense!
Talk about misconception, I have avoided prototyping for some reason...
from smqp.
Thanks! We have seen the results and they are way better. We have a version with even better results. We are working on it and we will do a PR when it's ready
from smqp.
how about if we change it to getters and setters?
from smqp.
or is that basically the same...
from smqp.
with getters these properties are enumerable, and if you do any Object assign, stringify... you are seen this "private" properties and use them too. With symbols, or making a prototype, you can avoid this, but it needs a big refactor
from smqp.
We did this change in the Message.js file:
import { generateId } from './shared';
export { Message };
const messageIdSymbol = Symbol.for('messageId');
const ttlSymbol = Symbol.for('ttl');
const pendingSymbol = Symbol.for('pending');
const consumedCallbackSymbol = Symbol.for('consumedCallback');
const consumedSymbol = Symbol.for('consumed');
const onConsumedSymbol = Symbol.for('onConsumed');
const publicMethods = ['consume', 'ack', 'nack', 'reject'];
function Message(fields = {}, content, properties = {}, onConsumed) {
if (!(this instanceof Message)) {
return new Message(fields, content, properties, onConsumed);
}
this[onConsumedSymbol] = onConsumed;
this[pendingSymbol] = false;
this[messageIdSymbol] = properties.messageId || `smq.mid-${generateId()}`;
const messageProperties = { ...properties, messageId: this[messageIdSymbol] };
const timestamp = (messageProperties.timestamp =
properties.timestamp || Date.now());
if (properties.expiration) {
this[ttlSymbol] = messageProperties.ttl =
timestamp + parseInt(properties.expiration);
}
this.fields = { ...fields, consumerTag: undefined };
this.content = content;
this.properties = messageProperties;
for (let i = 0; i < publicMethods.length; i++) {
const fn = publicMethods[i];
this[fn] = Message.prototype[fn].bind(this);
}
}
// These assignations are called only once
Object.defineProperty(Message.prototype, 'messageId', {
get() {
return this[messageIdSymbol];
},
});
Object.defineProperty(Message.prototype, 'ttl', {
get() {
return this[ttlSymbol];
},
});
Object.defineProperty(Message.prototype, 'consumerTag', {
get() {
return this.fields.consumerTag;
},
});
Object.defineProperty(Message.prototype, 'pending', {
get() {
return this[pendingSymbol];
},
});
Message.prototype.consume = function({ consumerTag } = {}, consumedCb) {
this[pendingSymbol] = true;
this.fields.consumerTag = consumerTag;
this[consumedCallbackSymbol] = consumedCb;
};
Message.prototype.reset = function() {
this[pendingSymbol] = false;
};
Message.prototype.ack = function(allUpTo) {
if (!this[pendingSymbol]) return;
this[consumedSymbol]('ack', allUpTo);
};
Message.prototype.nack = function(allUpTo, requeue = true) {
if (!this[pendingSymbol]) return;
this[consumedSymbol]('nack', allUpTo, requeue);
};
Message.prototype.reject = function(requeue = true) {
this.nack(false, requeue);
};
Message.prototype[consumedSymbol] = function(operation, allUpTo, requeue) {
[
this[consumedCallbackSymbol],
this[onConsumedSymbol],
this.reset.bind(this),
].forEach((fn) => {
if (fn) fn(this, operation, allUpTo, requeue);
});
};
we have tested this code:
const {Message} = require('../dist/src/Message');
const nIteration = 3000000;
for (let i = 0; i < nIteration; i++) {
Message();
}
And the results of the node --prof
are very promised:
Original Message.js
:
Statistical profiling result from isolate-0x5178530-28375-v8.log, (9882 ticks, 0 unaccounted, 0 excluded).
[Shared libraries]:
ticks total nonlib name
8147 82.4% .nvm/versions/node/v14.17.0/bin/node
362 3.7% /lib/x86_64-linux-gnu/libc-2.27.so
64 0.6% [vdso]
3 0.0% /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25
[JavaScript]:
ticks total nonlib name
408 4.1% 31.2% LazyCompile: *<anonymous> smqp/perf/message.js:1:1
6 0.1% 0.5% LazyCompile: *Message smqp/dist/src/Message.js:10:17
[C++]:
ticks total nonlib name
521 5.3% 39.9% __fmod_finite
68 0.7% 5.2% __libc_malloc
60 0.6% 4.6% mprotect
45 0.5% 3.4% cfree
38 0.4% 2.9% __pthread_cond_timedwait
21 0.2% 1.6% fmod
18 0.2% 1.4% __lll_lock_wait
17 0.2% 1.3% __pthread_cond_signal
14 0.1% 1.1% munmap
13 0.1% 1.0% operator delete(void*)
13 0.1% 1.0% mmap
12 0.1% 0.9% operator new(unsigned long, std::nothrow_t const&)
10 0.1% 0.8% __GI___pthread_mutex_lock
9 0.1% 0.7% write
9 0.1% 0.7% __lll_unlock_wake
6 0.1% 0.5% do_futex_wait.constprop.1
5 0.1% 0.4% operator delete[](void*)
3 0.0% 0.2% __GI___pthread_mutex_unlock
2 0.0% 0.2% operator new(unsigned long)
2 0.0% 0.2% __pthread_cond_wait
1 0.0% 0.1% sysconf
1 0.0% 0.1% __new_sem_wait
1 0.0% 0.1% __clock_gettime
1 0.0% 0.1% __GI___pthread_mutex_init
1 0.0% 0.1% _IO_file_xsputn
1 0.0% 0.1% _IO_default_xsputn
[Summary]:
ticks total nonlib name
414 4.2% 31.7% JavaScript
892 9.0% 68.3% C++
3239 32.8% 248.0% GC
8576 86.8% Shared libraries
[C++ entry points]:
ticks cpp total name
521 77.0% 5.3% __fmod_finite
64 9.5% 0.6% __libc_malloc
35 5.2% 0.4% cfree
21 3.1% 0.2% fmod
13 1.9% 0.1% operator delete(void*)
12 1.8% 0.1% operator new(unsigned long, std::nothrow_t const&)
5 0.7% 0.1% operator delete[](void*)
2 0.3% 0.0% write
1 0.1% 0.0% operator new(unsigned long)
1 0.1% 0.0% mprotect
1 0.1% 0.0% __lll_lock_wait
1 0.1% 0.0% __clock_gettime
[Bottom up (heavy) profile]:
Note: percentage shows a share of a particular caller in the total
amount of its parent calls.
Callers occupying less than 1.0% are not shown.
ticks parent name
8147 82.4% .nvm/versions/node/v14.17.0/bin/node
5171 63.5% .nvm/versions/node/v14.17.0/bin/node
4842 93.6% LazyCompile: *<anonymous> smqp/perf/message.js:1:1
4842 100.0% LazyCompile: ~Module._compile internal/modules/cjs/loader.js:1022:37
4842 100.0% LazyCompile: ~Module._extensions..js internal/modules/cjs/loader.js:1077:37
4842 100.0% LazyCompile: ~Module.load internal/modules/cjs/loader.js:921:33
259 5.0% .nvm/versions/node/v14.17.0/bin/node
257 99.2% LazyCompile: *<anonymous> smqp/perf/message.js:1:1
257 100.0% LazyCompile: ~Module._compile internal/modules/cjs/loader.js:1022:37
257 100.0% LazyCompile: ~Module._extensions..js internal/modules/cjs/loader.js:1077:37
200 2.5% LazyCompile: *<anonymous> smqp/perf/message.js:1:1
200 100.0% LazyCompile: ~Module._compile internal/modules/cjs/loader.js:1022:37
200 100.0% LazyCompile: ~Module._extensions..js internal/modules/cjs/loader.js:1077:37
200 100.0% LazyCompile: ~Module.load internal/modules/cjs/loader.js:921:33
200 100.0% LazyCompile: ~Module._load internal/modules/cjs/loader.js:709:24
521 5.3% __fmod_finite
521 100.0% .nvm/versions/node/v14.17.0/bin/node
521 100.0% .nvm/versions/node/v14.17.0/bin/node
521 100.0% LazyCompile: *<anonymous> smqp/perf/message.js:1:1
521 100.0% LazyCompile: ~Module._compile internal/modules/cjs/loader.js:1022:37
521 100.0% LazyCompile: ~Module._extensions..js internal/modules/cjs/loader.js:1077:37
408 4.1% LazyCompile: *<anonymous> smqp/perf/message.js:1:1
408 100.0% LazyCompile: ~Module._compile internal/modules/cjs/loader.js:1022:37
408 100.0% LazyCompile: ~Module._extensions..js internal/modules/cjs/loader.js:1077:37
408 100.0% LazyCompile: ~Module.load internal/modules/cjs/loader.js:921:33
408 100.0% LazyCompile: ~Module._load internal/modules/cjs/loader.js:709:24
408 100.0% LazyCompile: ~executeUserEntryPoint internal/modules/run_main.js:65:31
362 3.7% /lib/x86_64-linux-gnu/libc-2.27.so
52 14.4% .nvm/versions/node/v14.17.0/bin/node
42 80.8% .nvm/versions/node/v14.17.0/bin/node
41 97.6% LazyCompile: *<anonymous> smqp/perf/message.js:1:1
41 100.0% LazyCompile: ~Module._compile internal/modules/cjs/loader.js:1022:37
41 100.0% LazyCompile: ~Module._extensions..js internal/modules/cjs/loader.js:1077:37
1 2.4% LazyCompile: *Message smqp/dist/src/Message.js:10:17
1 100.0% Eval: ~<anonymous> smqp/perf/message.js:1:1
1 100.0% LazyCompile: ~Module._compile internal/modules/cjs/loader.js:1022:37
10 19.2% LazyCompile: *<anonymous> smqp/perf/message.js:1:1
10 100.0% LazyCompile: ~Module._compile internal/modules/cjs/loader.js:1022:37
10 100.0% LazyCompile: ~Module._extensions..js internal/modules/cjs/loader.js:1077:37
10 100.0% LazyCompile: ~Module.load internal/modules/cjs/loader.js:921:33
New Message.js
:
Statistical profiling result from isolate-0x4af3530-26744-v8.log, (2305 ticks, 1 unaccounted, 0 excluded).
[Shared libraries]:
ticks total nonlib name
1204 52.2% .nvm/versions/node/v14.17.0/bin/node
86 3.7% [vdso]
29 1.3% /lib/x86_64-linux-gnu/libc-2.27.so
2 0.1% /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25
[JavaScript]:
ticks total nonlib name
255 11.1% 25.9% LazyCompile: *Message smqp/dist/src/Message.js:18:17
55 2.4% 5.6% LazyCompile: *<anonymous> smqp/perf/message.js:1:1
[C++]:
ticks total nonlib name
548 23.8% 55.7% __fmod_finite
35 1.5% 3.6% cfree
30 1.3% 3.0% __libc_malloc
12 0.5% 1.2% operator new(unsigned long, std::nothrow_t const&)
12 0.5% 1.2% __pthread_cond_signal
10 0.4% 1.0% fmod
8 0.3% 0.8% write
4 0.2% 0.4% operator delete(void*)
3 0.1% 0.3% operator delete[](void*)
2 0.1% 0.2% fwrite
1 0.0% 0.1% std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&)
1 0.0% 0.1% std::string::_Rep::_M_destroy(std::allocator<char> const&)
1 0.0% 0.1% std::ostream::sentry::sentry(std::ostream&)
1 0.0% 0.1% std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
1 0.0% 0.1% std::__detail::_Prime_rehash_policy::_M_next_bkt(unsigned long) const
1 0.0% 0.1% do_futex_wait.constprop.1
1 0.0% 0.1% __open_nocancel
1 0.0% 0.1% __lll_unlock_wake
1 0.0% 0.1% __GI___pthread_mutex_unlock
[Summary]:
ticks total nonlib name
310 13.4% 31.5% JavaScript
673 29.2% 68.4% C++
49 2.1% 5.0% GC
1321 57.3% Shared libraries
1 0.0% Unaccounted
[C++ entry points]:
ticks cpp total name
548 85.4% 23.8% __fmod_finite
33 5.1% 1.4% cfree
28 4.4% 1.2% __libc_malloc
12 1.9% 0.5% operator new(unsigned long, std::nothrow_t const&)
10 1.6% 0.4% fmod
4 0.6% 0.2% operator delete(void*)
3 0.5% 0.1% write
3 0.5% 0.1% operator delete[](void*)
1 0.2% 0.0% __open_nocancel
[Bottom up (heavy) profile]:
Note: percentage shows a share of a particular caller in the total
amount of its parent calls.
Callers occupying less than 1.0% are not shown.
ticks parent name
1204 52.2% .nvm/versions/node/v14.17.0/bin/node
567 47.1% LazyCompile: *Message smqp/dist/src/Message.js:18:17
564 99.5% LazyCompile: *<anonymous> smqp/perf/message.js:1:1
564 100.0% LazyCompile: ~Module._compile internal/modules/cjs/loader.js:1022:37
564 100.0% LazyCompile: ~Module._extensions..js internal/modules/cjs/loader.js:1077:37
564 100.0% LazyCompile: ~Module.load internal/modules/cjs/loader.js:921:33
467 38.8% .nvm/versions/node/v14.17.0/bin/node
276 59.1% .nvm/versions/node/v14.17.0/bin/node
274 99.3% LazyCompile: *Message smqp/dist/src/Message.js:18:17
272 99.3% LazyCompile: *<anonymous> smqp/perf/message.js:1:1
272 100.0% LazyCompile: ~Module._compile internal/modules/cjs/loader.js:1022:37
148 31.7% LazyCompile: *Message smqp/dist/src/Message.js:18:17
148 100.0% LazyCompile: *<anonymous> smqp/perf/message.js:1:1
148 100.0% LazyCompile: ~Module._compile internal/modules/cjs/loader.js:1022:37
148 100.0% LazyCompile: ~Module._extensions..js internal/modules/cjs/loader.js:1077:37
31 6.6% LazyCompile: ~compileForInternalLoader internal/bootstrap/loaders.js:270:27
31 100.0% LazyCompile: ~nativeModuleRequire internal/bootstrap/loaders.js:303:29
4 12.9% Eval: ~<anonymous> internal/modules/esm/loader.js:1:1
4 100.0% LazyCompile: ~compileForInternalLoader internal/bootstrap/loaders.js:270:27
4 12.9% Eval: ~<anonymous> events.js:1:1
4 100.0% LazyCompile: ~compileForInternalLoader internal/bootstrap/loaders.js:270:27
3 9.7% Eval: ~<anonymous> internal/source_map/source_map_cache.js:1:1
3 100.0% LazyCompile: ~compileForInternalLoader internal/bootstrap/loaders.js:270:27
3 9.7% Eval: ~<anonymous> internal/bootstrap/node.js:1:1
2 6.5% LazyCompile: ~initializeCJSLoader internal/bootstrap/pre_execution.js:425:29
2 100.0% LazyCompile: ~prepareMainThreadExecution internal/bootstrap/pre_execution.js:20:36
2 6.5% Eval: ~<anonymous> internal/process/esm_loader.js:1:1
2 100.0% LazyCompile: ~compileForInternalLoader internal/bootstrap/loaders.js:270:27
1 3.2% LazyCompile: ~setupPrepareStackTrace internal/bootstrap/node.js:252:32
1 100.0% Eval: ~<anonymous> internal/bootstrap/node.js:1:1
1 3.2% LazyCompile: ~setupBuffer internal/bootstrap/node.js:300:21
1 100.0% Eval: ~<anonymous> internal/bootstrap/node.js:1:1
1 3.2% LazyCompile: ~initializeReport internal/bootstrap/pre_execution.js:167:26
1 100.0% LazyCompile: ~prepareMainThreadExecution internal/bootstrap/pre_execution.js:20:36
1 3.2% LazyCompile: ~createGlobalConsole internal/bootstrap/node.js:317:29
1 100.0% Eval: ~<anonymous> internal/bootstrap/node.js:1:1
1 3.2% Eval: ~<anonymous> internal/url.js:1:1
1 100.0% LazyCompile: ~compileForInternalLoader internal/bootstrap/loaders.js:270:27
1 3.2% Eval: ~<anonymous> internal/timers.js:1:1
1 100.0% LazyCompile: ~compileForInternalLoader internal/bootstrap/loaders.js:270:27
1 3.2% Eval: ~<anonymous> internal/process/task_queues.js:1:1
1 100.0% LazyCompile: ~compileForInternalLoader internal/bootstrap/loaders.js:270:27
1 3.2% Eval: ~<anonymous> internal/modules/esm/get_source.js:1:1
1 100.0% LazyCompile: ~compileForInternalLoader internal/bootstrap/loaders.js:270:27
1 3.2% Eval: ~<anonymous> internal/modules/cjs/helpers.js:1:1
1 100.0% LazyCompile: ~compileForInternalLoader internal/bootstrap/loaders.js:270:27
1 3.2% Eval: ~<anonymous> internal/fs/promises.js:1:1
1 100.0% LazyCompile: ~compileForInternalLoader internal/bootstrap/loaders.js:270:27
1 3.2% Eval: ~<anonymous> internal/console/global.js:1:1
1 100.0% LazyCompile: ~compileForInternalLoader internal/bootstrap/loaders.js:270:27
1 3.2% Eval: ~<anonymous> fs.js:1:1
1 100.0% LazyCompile: ~compileForInternalLoader internal/bootstrap/loaders.js:270:27
1 3.2% Eval: ~<anonymous> buffer.js:1:1
1 100.0% LazyCompile: ~compileForInternalLoader internal/bootstrap/loaders.js:270:27
134 11.1% LazyCompile: *<anonymous> smqp/perf/message.js:1:1
134 100.0% LazyCompile: ~Module._compile internal/modules/cjs/loader.js:1022:37
134 100.0% LazyCompile: ~Module._extensions..js internal/modules/cjs/loader.js:1077:37
134 100.0% LazyCompile: ~Module.load internal/modules/cjs/loader.js:921:33
134 100.0% LazyCompile: ~Module._load internal/modules/cjs/loader.js:709:24
548 23.8% __fmod_finite
548 100.0% .nvm/versions/node/v14.17.0/bin/node
548 100.0% .nvm/versions/node/v14.17.0/bin/node
546 99.6% LazyCompile: *Message smqp/dist/src/Message.js:18:17
545 99.8% LazyCompile: *<anonymous> smqp/perf/message.js:1:1
545 100.0% LazyCompile: ~Module._compile internal/modules/cjs/loader.js:1022:37
255 11.1% LazyCompile: *Message smqp/dist/src/Message.js:18:17
254 99.6% LazyCompile: *<anonymous> smqp/perf/message.js:1:1
254 100.0% LazyCompile: ~Module._compile internal/modules/cjs/loader.js:1022:37
254 100.0% LazyCompile: ~Module._extensions..js internal/modules/cjs/loader.js:1077:37
254 100.0% LazyCompile: ~Module.load internal/modules/cjs/loader.js:921:33
254 100.0% LazyCompile: ~Module._load internal/modules/cjs/loader.js:709:24
86 3.7% [vdso]
84 97.7% .nvm/versions/node/v14.17.0/bin/node
84 100.0% LazyCompile: *Message smqp/dist/src/Message.js:18:17
84 100.0% LazyCompile: *<anonymous> smqp/perf/message.js:1:1
84 100.0% LazyCompile: ~Module._compile internal/modules/cjs/loader.js:1022:37
84 100.0% LazyCompile: ~Module._extensions..js internal/modules/cjs/loader.js:1077:37
55 2.4% LazyCompile: *<anonymous> smqp/perf/message.js:1:1
55 100.0% LazyCompile: ~Module._compile internal/modules/cjs/loader.js:1022:37
55 100.0% LazyCompile: ~Module._extensions..js internal/modules/cjs/loader.js:1077:37
55 100.0% LazyCompile: ~Module.load internal/modules/cjs/loader.js:921:33
55 100.0% LazyCompile: ~Module._load internal/modules/cjs/loader.js:709:24
55 100.0% LazyCompile: ~executeUserEntryPoint internal/modules/run_main.js:65:31
35 1.5% cfree
33 94.3% .nvm/versions/node/v14.17.0/bin/node
33 100.0% .nvm/versions/node/v14.17.0/bin/node
33 100.0% LazyCompile: *Message smqp/dist/src/Message.js:18:17
33 100.0% LazyCompile: *<anonymous> smqp/perf/message.js:1:1
33 100.0% LazyCompile: ~Module._compile internal/modules/cjs/loader.js:1022:37
30 1.3% __libc_malloc
28 93.3% .nvm/versions/node/v14.17.0/bin/node
28 100.0% .nvm/versions/node/v14.17.0/bin/node
28 100.0% LazyCompile: *Message smqp/dist/src/Message.js:18:17
27 96.4% LazyCompile: *<anonymous> smqp/perf/message.js:1:1
27 100.0% LazyCompile: ~Module._compile internal/modules/cjs/loader.js:1022:37
1 3.6% LazyCompile: *Message smqp/dist/src/Message.js:18:17
1 100.0% Eval: ~<anonymous> smqp/perf/message.js:1:1
29 1.3% /lib/x86_64-linux-gnu/libc-2.27.so
24 82.8% .nvm/versions/node/v14.17.0/bin/node
24 100.0% .nvm/versions/node/v14.17.0/bin/node
24 100.0% LazyCompile: *Message smqp/dist/src/Message.js:18:17
24 100.0% LazyCompile: *<anonymous> smqp/perf/message.js:1:1
24 100.0% LazyCompile: ~Module._compile internal/modules/cjs/loader.js:1022:37
from smqp.
We tried to maintain the same external contract for the Message function and returned object, and all the test are working.
If you like the change, we can prepare a PR with this applied in every function
from smqp.
Please do! Looks very promising!
from smqp.
Not sure why but recent version of smqp has also big impact on memory consumption.
Before:
- when hundred of bpmn engine instances were created it took more than 3GB of memory
Now (after upgrade):
- when hundreds of bpmn engine instances were created it seems to run normally
from smqp.
That’s great!
Not entirely sure why prototyping has this effect. But the number of LazyCompiles decline a lot when compared to the closure version. Since object creation is expensive I guess that precompiled “classes” renders objects faster. Much faster. Kind of makes sense. Sorry for not realizing this earlier. And thank you to the owners of this issue.
from smqp.
@roberto-naharro and I have been working on more optimizations, they are available in #6
Kindest regards!
from smqp.
There shouldn't be such a big difference, both version are doing basically the same (class is just syntax sugar to assign to the prototype typing a little bit less) 🤔
I wasn't aware that you had already finished all the optimizations using the prototypes, we were trying to save you some work with this one 😅
from smqp.
Sorry for the double work. You could check that you receive the same profiling result on your end. I tend to get things wrong.
from smqp.
No problem at all, it was nice to get some extra insights :D
I tested with Message and your branch is 9% faster 👍
from smqp.
The Message.js is all yours. Ctrl+c+v. :)
from smqp.
Now I have exhausted the possibility of using WeakMap and other perf tweaks but nothing has proven to be faster or less CPU intense than the current solution. Prototyping with symbols seems to be the best solution. Over and out.
from smqp.
Related Issues (3)
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from smqp.