LC7 and 8 - Non responsive processing large text files

Mark Waddingham mark at livecode.com
Fri Apr 15 03:43:03 EDT 2016


On 2016-04-15 08:59, Roland Huettmann wrote:
> I think it is important to know how to handle "big" data with files, in
> memory and placing in fields. And of course in a future nearby 8.1 
> version
> (or sooner?) those in need would love to see this taken care of in the
> engine.

I don't think the problem here is whether the engine has the facilities 
to process large files - it clearly does given the number of examples of 
how to do it that have been provided ;)

The issue here is how to keep a UI responsive on the Desktop whilst 
running a long processing operation - this isn't a problem unique to 
LiveCode it is one which pertinent to all languages on all OSes.

 From what I can understand of your use-case you are wanting to index an 
*exceptionally large* file so that you can look up things from it at a 
later date. Indeed, it seems to me that the problem you are trying to 
solve falls into two pieces:

   1) Process the very large file and produce an index of 'points of 
interest' in the file.

   2) Subsequently use the index to perform the main function of your 
application.

With this in mind, I'd suggest considering separating these two parts 
and run them in separate processes.
The foreground (UI) application can launch the second process to 
generate the index and provide a simple progress update periodically 
without having any impact on the performance of its job, and then when 
that operation is completed the foreground application can load the 
index to use.

The LiveCode Installer (albeit no longer used on Mac) works like this. 
It is a single application which can run in two modes. In the foreground 
mode you see the UI which you interact with, but when you finally get to 
the 'install' button, when you click that it launches a background 
process which runs a installation script - it feeds back progress 
information back to the foreground process at suitable intervals so that 
the UI can update a progress bar. (Admittedly the installer *has* to 
work this way as the background 'slave' process has to run with 
administrator rights, however it also happily solves the UI progress bar 
update / cancellation problem though too).

This is basically what you could call a 'master/slave' pattern. You have 
a master process which provides the UI and the application's main 
function, and a slave process which is run and controlled by the master 
during indexing operations. This model has all kinds of advantages - for 
example, you can rerun the slave 'indexing' process whilst the user is 
still using an existing index; or indeed launch several slave processes 
to index multiple files at once.

In LiveCode such a pattern can be implemented in the master using an 
'open process read/write process close process' loop; whilst all the 
slave has to do is read from stdin and write to stdout.

The above might seem a little opaque - however, it might help to have a 
look at:

   
https://github.com/livecode/livecode/blob/develop/builder/installer_utilities.livecodescript

Which is the main installer implementation. When run as slave, the only 
handler which runs is 'runInstallerActions'; and when run as master 
there is a UI which runs a 'send in time' loop 'installerMonitor' to 
talk to the slave. The main entry point to the installer application is 
a startup handler which decides (by looking at the command line 
arguments) what it should do:

on startup
    local tAction

    if $1 is "install" then
       put "install" into tAction
    else if $1 is "doinstall" then
       put "doinstall" into tAction
    else if $1 is "uninstall" then
       put "uninstall" into tAction
    else if $1 is "douninstall" then
       put "douninstall" into tAction
    else
       set the itemDelimiter to slash
       if the last item of $0 contains "setup" then
          put "uninstall" into tAction
       else
          put "install" into tAction
       end if
    end if

    switch tAction
       case "install"
          if $2 is "noui" then
             runFacelessInstall
          else
             hide me
             send "runInstallerUI" to me in 0 millisecs
          end if
          break
       case "uninstall"
          if $2 is "noui" then
             runFacelessUninstall
          else
             hide me
             send "runUninstallerUI" to me in 0 millisecs
          end if
          break
       case "doinstall"
          runInstallerActions
          break
       case "douninstall"
          runUninstallerActions
          break
       default
          quit 1
    end switch
end startup

Here 'install' and 'uninstall' run the master UI (the default is 
'install' if no arguments are specified); whilst doinstall/douninstall 
run the slave.

Anyway, I'll try to find some time to distill out a skeleton application 
which does this - it seems like it might be useful thing as an example 
:)

Warmest Regards,

Mark.

P.S. One could argue that 'multi-threading' might help here - but it is 
actually absolutely no different in effect from splitting into two 
processes. Indeed, for this kind of thing separate processes is a much 
much better idea as it completely insulates the master from the slave 
and is much more failsafe as the two processes run in their own memory 
spaces with their own resources and only communicate over a very thin 
connection. i.e. Problems in one cannot propagate to the other. It also 
provides more options in terms of running the indexing operation - it 
doesn't necessarily need to be done in response to the master 
application, indexing becomes an operation in its own right which can be 
managed in any way which might be required.

-- 
Mark Waddingham ~ mark at livecode.com ~ http://www.livecode.com/
LiveCode: Everyone can create apps




More information about the use-livecode mailing list