Jump to content

[Solved] The Run() function takes about 850ms


Guest
 Share

Recommended Posts

Hello, my code execute "command line" program (program with no GUI) with Run() function.
During the execution of the external program I get it's output with StdoutRead() function.

 

My problem is that it takes some time until the Run() function finish to open the external program. It takes ~850ms.
I didn't expect that.. I did not take into account that such a thing could happen.. It is not RunWait but it act like this.

Is there any way to optimize it?

My requirements:

* Run the EXE file in less then 100ms
* Run it in HIDE mode
* Get it's input with StdoutRead / other mathed - in realtime (not after the EXE file was done doing it job)

 

The exe file is 38mb

Edited by Guest
Link to comment
Share on other sites

do we get to see your code and compile options?

And just so we are clear on the concept: you want AutoIt to run cmd to execute something and then wait for cmd to tell AutoIt what that something returned? And we are trying to shave off milliseconds? From AutoIt?

Edited by iamtheky

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

Link to comment
Share on other sites

These are the critical lines in my code I wrote:

Run the EXE with the parameters:

$Commander_Pid = Run('"'&$Commander_aJobList[0][$Commander_C_idx_ExeFile]&'" '&$Commander_aJobList[0][$Commander_C_idx_Command], '', @SW_HIDE,$STDERR_MERGED)
If @error Or $Commander_aJobList[0][$Commander_C_idx_MaxWaitTime] = $Commander_C_MaxWaitTime_NoWait Then Return _ArrayDelete($Commander_aJobList,0) ; In error case or no-wait just exit and delete the job

 

Read the input:

; If there is function to call at the end, prepere the output for it (to send it later)
If $stdReadMode Then
$tmp = StdoutRead($Commander_Pid)
If Not @error Then $stdRead &= $tmp
EndIf

 

Call the function

; If the job set to call to function then we call it now
            If $sCallFunction Then
                Local $Output[$Commander_C_output_idxmax]
                $Output[$Commander_C_output_idx_JobState] = $iJobState
                $Output[$Commander_C_output_idx_CmdRead] = $stdRead

                ; Clean memory of $stdRead
                $stdRead = 0

                ; Call to the function

                If $sCallFunction_Arg7 <> Null Then Return Call($sCallFunction,$Output,$sCallFunction_Arg1,$sCallFunction_Arg2,$sCallFunction_Arg3, _
                                                                $sCallFunction_Arg4, $sCallFunction_Arg5, $sCallFunction_Arg6, $sCallFunction_Arg7)
                If $sCallFunction_Arg6 <> Null Then Return Call($sCallFunction,$Output,$sCallFunction_Arg1,$sCallFunction_Arg2,$sCallFunction_Arg3, _
                                                                $sCallFunction_Arg4, $sCallFunction_Arg5, $sCallFunction_Arg6)
                If $sCallFunction_Arg5 <> Null Then Return Call($sCallFunction,$Output,$sCallFunction_Arg1,$sCallFunction_Arg2,$sCallFunction_Arg3, _
                                                                $sCallFunction_Arg4, $sCallFunction_Arg5)
                If $sCallFunction_Arg4 <> Null Then Return Call($sCallFunction,$Output,$sCallFunction_Arg1,$sCallFunction_Arg2,$sCallFunction_Arg3, _
                                                                $sCallFunction_Arg4)
                If $sCallFunction_Arg3 <> Null Then Return Call($sCallFunction,$Output,$sCallFunction_Arg1,$sCallFunction_Arg2,$sCallFunction_Arg3)
                If $sCallFunction_Arg2 <> Null Then Return Call($sCallFunction,$Output,$sCallFunction_Arg1,$sCallFunction_Arg2)
                If $sCallFunction_Arg1 <> Null Then Return Call($sCallFunction,$Output,$sCallFunction_Arg1)
                Return Call($sCallFunction,$Output)
            EndIf

 

Almost everything works great. The whole process happens without stopping the script .. except for the part of the Run() function..

 

Link to comment
Share on other sites

#include <AutoItConstants.au3>
#include <MsgBoxConstants.au3>


Func Example()
    Local $iPID = Run('C:\Windows\system32\cmd.exe', @SystemDir, @SW_SHOW, $STDIN_CHILD + $STDERR_MERGED)


    StdinWrite($iPID,'<External exe file path> <PUT THE COMMAND HERE>'&@CRLF)

    Local $sOutput = "" ; Store the output of StdoutRead to a variable.

    $timer = TimerInit()
    Do
        ToolTip('running')
        $sOutput &= StdoutRead($iPID) ;
    Until TimerDiff($timer) > 2000  ; <----------------------------- INSTED OF THIS I NEED CODE TO CHECK IF THE EXTERNAL EXE PROCESS WAS CLOSED


EndFunc   ;==>Example

 

Please help me here ^

I know why it happans.. this is something to do with the external with certain commands.. It is not something in my code that causing this

Link to comment
Share on other sites

Why not use something like this:

While ProcessExists($iPID)
        ToolTip('running')
        $sOutput &= StdoutRead($iPID)
    WEnd

 

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

and can you build your command prior, rather than using stdinwrite?  I have to think you are catching a penalty to wait for cmd return that it is started and that its ok to write stuff to the stream.

Edited by iamtheky

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

Link to comment
Share on other sites

1 hour ago, water said:

Why not use something like this:

While ProcessExists($iPID)
        ToolTip('running')
        $sOutput &= StdoutRead($iPID)
    WEnd

 

Because that means I need to know the PID of the process and it takes about 850ms to have a PID. during  the 850ms the script freezes.

So I thought about running the EXE indirectly - via cmd. In this way cmd runs the exe so the 850ms will not stop the script.
It also means that I do not get the PID from the start. I only get the cmd's PID.

But I do not think I need the pid of the exe for knowing if it closed/finish it job.
  I have a way how to check it but I don't know if it good one:

I noticed that when the external exe done to do it job (and it closed), I get this string from StdoutRead($iPID)

Quote


S:\test>


"S:\test" is the "workingdir" parameter that I gave to the run function.
It seems that that's the sign I am looking for to know if the external exe done with it job.
So I think to check it this way:

Until StringStripWS($sRead,3) = @ScriptDir&'>'

It works.

Is it safe method? Is the cmd can produce  unexpected behaviour so it will not return  this kind of string format ( @ScriptDir&'>' ) ( Assuming  that I call to Run function with the parameter $workingdir set to @ScriptDir) ?
I don't know why it add ">" and the enters..

 

iamtheky, sorry, I didn't understand what did you mean

Edited by Guest
Link to comment
Share on other sites

in your first example it was just a cmd + parameters

in your example in #4 you have a stdinwrite instead of parameters such that I'm not even sure what is going on, but that part is probably taking up unnecessary clock.

Edited by iamtheky

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

Link to comment
Share on other sites

17 minutes ago, iamtheky said:

in your first example it was just a cmd + parameters

in your example in #4 you have a stdinwrite instead of parameters such that I'm not even sure what is going on, but that part is probably taking up unnecessary clock.

It was not cmd + parameters. It was external exe file with parameters. the external exe have no gui. it have only command line interface.
In the example in #4 it was cmd "with parameters"...

The reson why I think to do it in this way is because I planing to keep the cmd running always until the program closed.
So in this design the the parameters can't be pass through the run function. yes, they can pass only on the first run (when I open cmd with run() ). but after that point I can't use thr Run() function to pass new parameters to cmd for obvious reason.

The 
reason for why I thought  to use cmd at the first place I wrote in #7.
 

Edited by Guest
Link to comment
Share on other sites

Are you arguing semantics about code?  

I super don't care what the file you are calling from command does.  I am only focused on cmd.exe and your use of that.

This is the only point I am trying to make:

There are a metric shit ton of things that cmd.exe does very safely for no good reason at all, I believe the  second method you use encounters multiple penalties that the first effort would not. 

Have you tried running the exe and piping the output to a file thus eliminating the need to stay open for additional time?

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

Link to comment
Share on other sites

Using file to get the output is bad idea because it  depends on your hard disk speed (that much less fast then the RAM) so I didn't tried that.
And anyway I need to get the info also while it still created. so StdoutRead() seems the best and most natural way. 
Piping the output to a file  will also not solve the main problem - the 850ms freezing will still be.

The Run() function still waiting to get the PID of the exe file which takes some almost 1 second to load.
I don't know about
function like Run() but not waiting  for the pid.. If there was function exactly like Run() but without the waiting to the pid part (So I will handle it in my loop..) Then this can probably be the beginning of the solution. But I don't know about such function..
so the best option I  thought about is to use external process so the external process will run the EXE. I tring to avoid from coding myself such external process (even if i have no problem to do so. i can use my _SharedVar udf) Because I think that such external process already exists - the cmd.exe.  But I think you're telling me that it is bad idea.. coding my own external process is a better idea?

 

EDIT:
 

Quote

The Run() function still waiting to get the PID of the exe file which takes some almost 1 second to load.
I don't know about
function like Run() but not waiting  for the pid.. If there was function exactly like Run() but without the waiting to the pid part (So I will handle it in my loop..) Then this can probably be the beginning of the solution. But I don't know about such function..

Maybe this function can do it?

https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx

 

I need to:
1) run the exe with command in hide mode
2) wait for it's $pid in my loop
3) using StdoutRead($pid) to read the output

 

Please ignore previous posts to avoid confusion

 

Edited by Guest
Link to comment
Share on other sites

speculation in lieu of an actual process of elimination....  My 14 log cmds take under 5sec to run if there is little/no data. 

I am also not a file system expert, are you sure cmd waits around for the write to disk?  I would guess the space is most likely allocated upon redirection and whether you choose another file or the current stream matters little.  (e.g.  Have you measured the time with and without the $STDIN_CHILD + $STDERR_MERGED)

if all we are measuring is how fast can you get cmd to do this, it would still be worth a shot in my estimation.

 

Edited by iamtheky

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

Link to comment
Share on other sites

Quote

Have you measured the time with and without the $STDIN_CHILD + $STDERR_MERGED)

Yes, I tested it even without anything - even without parameters to the exe. it was just Run(<exe path>) and it still took almost 1 second to start. Only with @ComSpec it takes fast.

 

But I was able to achieve the same behaviour I need with the help of StdinWrite() function. On second thought I prefer not to keep @ComSpec running always until the program close..

This is the alternative code. takes about up to 10ms insted of ~850ms.

 

But I want that it will work in a way that @ComSpec will closed natively when it's children process closed. I guessing it can be achieved if I call to @ComSpec in defferent way..

 

EDIT:
Only If I add " /c " after @ComSpec it works with that behaviour (@ComSpec close when it child process close) and I don't need StdinWrite() but it print the output on the SciTE console and I don't need this

EDIT:

You know what, I'll live with it.
I like it .. It's nice to have it's output on SciTE console. This is a good debug
.
I hope that if I close the perent process, then it child process will close also. i guess that this should happen because it is child process. I will just check it to make sure

 

EDIT:

Quote

i guess that this should happen because it is child process. I will just check it to make sure

Indeed, this behavior occurs.

Quote

but it print the output on the SciTE console and I don't need this

This behavior does not occurs for some reson. on the main project it act exactly as I wanted before.
 

So buttom line: my final solution was to replace

$Commander_Pid = Run('"'&$Commander_aJobList[0][$Commander_C_idx_ExeFile]&'" '&$Commander_aJobList[0][$Commander_C_idx_Command], '', @SW_HIDE,$STDERR_MERGED)

To

$Commander_Pid = Run( _
            @ComSpec&' /c ""'&$Commander_aJobList[0][$Commander_C_idx_ExeFile]&'" '&$Commander_aJobList[0][$Commander_C_idx_Command]&'', _
            @ScriptDir, _
            @SW_HIDE, _
            $STDIN_CHILD + $STDERR_MERGED)

 

Problem solved!

Edited by Guest
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...