Creating Buffers: What is the optimal way of creating a buffer from a different thread?

67 views
Skip to first unread message

Eric Yen

unread,
Nov 16, 2015, 11:43:58 PM11/16/15
to nodejs
Hi,

I was wondering could point me in the in the right direction.
I have a C library running in a thread #1. When works arrive in thread #1, work is queued on to a Queue, and the thread wakes up thread #2 through uv_async_send, which wakes up the libuv event loop. Thread #2 gets the work from the Queue and invokes v8.

A lot of the work enqueued by thread #1 is a small buffer of ~64kb that needs to be duplicated before it is enqueued. This memory duplication can be slow because of malloc. From my understanding of nodejs, small buffers in nodejs are allocated from a managed memory pool, avoiding the need to call malloc frequently.

What I would like to do is have thread #1 directly create a node::Buffer / Nan;:Buffer, add the work to Queue, and have the uv event loop woken up.

So here's my questions.
1)  How can I create an object in thread #1 that will persist in to the second thread?
One option would be to create a Persistent object and then clearing it once it's finished.
Second option, which I'm not sure would work, and I wouldn't know why it won't work, would be to create the buffer in thread #1 and Escaping it with an EscapableHandlescope. 

2) Is it even worth it?
My understanding is that I would have to create a v8::Locker in thread #1 to ensure thread safety.
Would creating and acquiring the v8::Locker be much slower than just malloc'ing a small buffer?

Thanks for the answers and insights in to v8/nodejs.
Eric

Ben Noordhuis

unread,
Nov 17, 2015, 12:11:28 PM11/17/15
to nod...@googlegroups.com
On Tue, Nov 17, 2015 at 5:29 AM, Eric Yen <er...@ericyen.com> wrote:
> Hi,
>
> I was wondering could point me in the in the right direction.
> I have a C library running in a thread #1. When works arrive in thread #1,
> work is queued on to a Queue, and the thread wakes up thread #2 through
> uv_async_send, which wakes up the libuv event loop. Thread #2 gets the work
> from the Queue and invokes v8.
>
> A lot of the work enqueued by thread #1 is a small buffer of ~64kb that
> needs to be duplicated before it is enqueued. This memory duplication can be
> slow because of malloc. From my understanding of nodejs, small buffers in
> nodejs are allocated from a managed memory pool, avoiding the need to call
> malloc frequently.
>
> What I would like to do is have thread #1 directly create a node::Buffer /
> Nan;:Buffer, add the work to Queue, and have the uv event loop woken up.
>
> So here's my questions.
> 1) How can I create an object in thread #1 that will persist in to the
> second thread?
> One option would be to create a Persistent object and then clearing it once
> it's finished.
> Second option, which I'm not sure would work, and I wouldn't know why it
> won't work, would be to create the buffer in thread #1 and Escaping it with
> an EscapableHandlescope.

You can create the Buffer object upfront in the main thread and wrap
it in a strong Persistent handle to prevent the GC from reclaiming it.
You will need to record the pointer to the Buffer's memory separately
because you're not allowed to call node::Buffer::Data() on a different
thread.

Alternatively, you can malloc() the memory on the worker thread and
turn it into a zero-copy Buffer on the main thread.

Put anything involving node.js or V8 on a different thread out of your
head, it won't be reliable (in the
crash-and-eat-your-data-not-reliable sense.)

> 2) Is it even worth it?
> My understanding is that I would have to create a v8::Locker in thread #1 to
> ensure thread safety.
> Would creating and acquiring the v8::Locker be much slower than just
> malloc'ing a small buffer?

Using a v8::Locker won't help because the main thread doesn't release
the isolate when it goes to sleep. Other threads won't be able to
claim it, they'll just wait forever.
Reply all
Reply to author
Forward
0 new messages