How do I make intensive computation in main process with renderer unaffected by it [SOLVED]


#1

I had impression, that if I required something in renderer with remote.require, then everything I invoke on those objects will be processed in main process. But looks like it’s not what I thought it is.
Here is an example:

# Renderer process
fib = remote.require './test'
$('#fib-start').click ->
  fib (result) -> console.log(result)

# test.coffee
f = (n) ->
    if n is 0
        0
    else if n is 1
        1
    else
        f(n-1) + f(n-2)

module.exports = (callback) ->
    setTimeout(->
        res = f(45)
        callback(res)
    , 0)

My expectation was that renderer process won’t be affected with computation involved. But when I run this my whole window freezes for 15 seconds while it computes.

[UPDATE]
The main question in the title is of my post is invalid in a first place. I don’t need (and shouldn’t) to do CPU intensive operations in main process at all - because this is the place where all window and OS management is happening and by loading it up I will hang window itself.

The right way to do this is the same as for any other node app - to use child_process.spawn or fork.


#2

See the documentation:

When you invoke methods of a remote object, call a remote function, or create a new object with the remote constructor (function), you are actually sending synchronous inter-process messages.

Emphasis added.


#3

As @leedohm points out remote.require is synchronous. You can use the ipc module directly for asynchronous communication between the processes.


#4

Thx, guys. Now I see.

I tried this:

But this still hangs whole window.


#5

Async messages work in a simple test application with electron-prebuilt@0.30.2:
https://gist.github.com/johnmuhl/f351b0e7f5d6650131b0


#6

@john I think I already made proper communication with IPC (see, I replaced my code before with gist also) The problem I have is that with intensive computation in main process hangs and freezes UI portion.


#7

It could be that the sending of the message can’t complete until the ipc.on returns. Since you’re performing the calculation in the event handler, it may be that you’re blocking the sender from knowing that the event was successfully received. Perhaps you can try:

  1. In the event handler, schedule the calculation to happen and return from the event handler
  2. Perform the calculation
  3. Send acknowledgement that the calculation is complete

#8

@leedohm if by “schedule the calculation” you mean put it into setTimeout(, 0), then I tried it already too.
Here is updated code with console.log numbers, that appear in the numerical order. Now after clicking a button I have 2 seconds of moving stuff around and then it freezes with colors wheel (on Mac means window is unresponsive)


#9

I’ve tried to use native child_process.fork functionality and it works well

But I still hope to find out if electron IPC communication and renderer/main processes capable of.


#10

Why do you want to do “intensive computation” in the main process? It is possible that there are other things going on between the main process (OS messages, menu item setup, etc) and the renderer process that you’re holding up by consuming all those resources.


#11

This is actually very good question. I frankly don’t know. I thought main process is something running on background doing nothing. Now all dots are connected in my head. First, indeed main process is not the place for that, and secondly the fact it responsible for window management and other OS communications explains why I have whole window freeze when I hang it.
Will update my initial post and update a title. thanks.


#12

How does one use “child_process.spawn or fork” when needing the electron api’s, for example in this question: Electron UI BrowserWindow freezes my main UI BrowserWindow


#13

Is the proposed solution the right answer to the problem ? should we fork things from the mainProcess ? or is there another more elegant solution ? Thank you


#14

If you want to do “intensive computation” you should do it in a separate process from whatever process you’re working in. Most often, that is the renderer process. If you’re doing something in the renderer process and need some heavy lifting done … create a new process from there. You don’t have to go to the main process to do it.


#15

You can make a new process by making a new and hidden BrowserWindow to run computations in. Just don’t show the window. It will have access to all Electron APIs.

This is definitely heavier than spawn or fork, but the benefit is it is easy to do while having Electron APIs.

Is there a better way to make a new process that doesn’t have all the browser APIs, but still has non-browser Electron APIs?

(maybe use a WebWorker)