garbage collection

40 views
Skip to first unread message

Tomas Neme

unread,
Sep 4, 2013, 4:54:13 PM9/4/13
to q-con...@googlegroups.com
What happens with "parent" promises when they're resolved but still have children alive?

I want to keep a promise living forever in my object to make sure some things that depend on async operations happen in the right order

So my idea was to do something like

this.chain = Q.resolve()

/// inside some method

this.chain = this.chain.then(function() {
  ret = Q.defer();
  asynCall(args, function(res) {
    ret.resolve(res);
  });
  return ret.promise;
});


So what will happen after a couple thousand calls to "some method"? Will that memory be freed, or
will all the intermediate promises be kept alive?

Is there another way to do this?

--
"The whole of Japan is pure invention. There is no such country, there are no such people" --Oscar Wilde

|_|0|_|
|_|_|0|
|0|0|0|

(\__/)
(='.'=)This is Bunny. Copy and paste bunny
(")_(") to help him gain world domination.

Kris Kowal

unread,
Sep 4, 2013, 6:16:03 PM9/4/13
to Q Continuum
This is a common pattern and should work fine, unless there are lurking bugs we have not collectively noticed.

The behavior depends quite a bit on who retains references. In this case, you’ll notice that this line—

```javascript
this.chain = this.chain.then …
``` 

—ensures that you are only retaining a reference to the most recently created promise. The remaining promises in the chain are inductively retained by two things: the work they are doing (`anyCall` retains the callback, retains the resolver, retains the promise) or the work they’re waiting on (the previous promise in the chain). As the work finishes, the previous promises will be released.

However, if work piles up faster than it is completed, you could have a scheduling problem that would saturate memory with pending promises, in the same way you would pile up callbacks if you did not have promises.

I am working on introducing streams, based on promises, iterators, and promise queues, that would help address this problem by putting an upper bound on how much work is scheduled. This is slated to land in Q-IO…eventually. I have an abandoned branch on the topic with some obsolete documentation in Q proper, starting here https://github.com/kriskowal/q/blob/streams/README.md#infinite-promise-queue

Kris Kowal


Tomas Neme

unread,
Sep 4, 2013, 7:16:40 PM9/4/13
to q-con...@googlegroups.com
> I am working on introducing streams, based on promises, iterators, and
> promise queues, that would help address this problem by putting an upper

that's amazing

In my use case, that shouldn't be an issue, but it's good to know,
there's that possible problem.

Tomas Neme

unread,
Sep 5, 2013, 9:39:51 AM9/5/13
to q-con...@googlegroups.com
About this, I'm having trouble implementing it..

so, to go with real code, it's like this

I've got


function melted(host, port, timeout) {
    //// stuff...
    this.commandQueue = Q.resolve();
}

melted.prototype.sendCommand = function(command) {
    logger.debug(this.uuid + " - Sending command: " + command);
    return this.mlt.sendCommand(command, "200 OK");
};


and then I've got a lot of methods that look like this

melted.prototype.stop = function() {
    //Stop
    return this.sendCommand("STOP U0");
};

that this.mlt.sendCommand returns a promise that I want to return to the caller. Now, I've also got this special method

melted.prototype.sendClip = function(clip, command) {
    /// stuff...
    var deferred = Q.defer();
    var self = this;
    fs.writeFile(xmlFile, xml.toString({pretty:true}), function(err){
        if (err) {
            deferred.reject(err);
        } else {
            logger.debug(self.uuid + " - File ready: " + xmlFile);
            deferred.resolve(self.sendCommand(command.replace("{xmlFile}", xmlFile)));
        }
    });
    return deferred.promise;
};

Which is buggy, because the calls to sendCommand are not necessarily sent in the order that sendClip was called.

How can I make sure the calls to sendCommand are done in the same order as the calls to sendClip?

I've thought this out:

melted.prototype.next = function(then) {
    var ret = Q.defer();
    this.commandQueue = this.commandQueue.then(function() {
        ret.resolve(function() {
            return then();
        });
    });
    return ret;
};


But I'm sure there must be some kind of shortcut, and I'm not even sure of how to use it, exactly, to avoid losing parallelization. i.e., I'd
like the calls to writeFile still to be made in parallel if possible, and just have the resolution of their callbacks to be done in the right order

Any clues?

Thank you
Tomas
Reply all
Reply to author
Forward
0 new messages