I have a couple of ideas too I would like to share, it's probably obvious.I use a huge program running at external desktop, and the only ways to get information from the program is by reading colors (imagesearch, pixelgetcolor and pixelsearch), reading window title or window size.Because I've made a 6k lines script to maximize effeciency, I've learn that these tips may reduce noticeable lags (when waiting for imagesearch to finnish).

1. Multiple boolean IF/OR/ANDSituation 1 - There is some functions - checkSlow(), checkFast() and checkFastest(). Those name just gives a hint about the time it takes for those functions to return a result. If testing if all of those gives true, the most efficient way is normally by putting the fastest function first, bedause if that one return 0, a multiple AND statement won't waste time calling the next function.

Good idea:

If ( checkFastest() && checkFast() && checkSlow() ) do something

If there is a multiple boolean AND operator (if I can call it so?) and each function call takes about the same time, it's a good idea to put first the function that is most likely to return 0. For multiple OR operators, inverse rules applies.

2. Multiple imagesearchImageSearch will be relatively slow when searching a large area of screen. If the image to match is likely to stay in same location between multiple imagesearch calls, it is a good idea to make the second imagesearch (after the first imagesearch where a match was found) to only search within the matching area that measure the same dimensions as the image file.

This would indicate that using the ".=" operator in conjunction with (when applicable) the explicit "." concatenation operator is fastest. That last bit surprises me... See Operators.Further testing indicates this is false. See my next post.

After 4,011 loops (of ten million concatenations using each method), no explicit "." syntax resulted in an average of 2.037523 sec. while with it had an average of 2.037380 sec. I imagine that's well within the margin of error of the test. In terms of speed, concatenation with or without the "." operator is identical.

Hi. I'm not where I talk so much about those tiny micro seconds one operator compares to another. Instead I focus on how to improve the kind of taksk that I know takes times, and how to make it as effective as possible.

Todays examle - Say I have 4 function, each normally takes noticeable time to complete. It might be a imagesearch for each function, so if possible - the goal is to run as few as possible function calls (one function return true if it had success).Most of explanation is to be found in comments.

#NoEnv; Recommended for performance and compatibility with future AutoHotkey releases.SendMode Input ; Recommended for new scripts due to its superior speed and reliability.SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.

; ---- AlmostThere -----

; Move function call one place forward in queue each time function is called (and returns true).; Purpose: For time consuming function calls (eg. imagesearch where several different images may be found) - we want that the function that most oftens returns true should be called first (in a list of functions).; Weakness - if it turns out that two of the functions alternates between return true - those two might just swap place forever - without actually move to the begin of the queue.; Possible solutions for this problem:; 1. Always swap with first in queue (might not be most effective method when times goes by, as less often functions that is only true once in a while); 2. Add another table that counts when each functions returns true, and sorts by number of return-true.

; Create the ini file if it doesn't already exists (may not be neccesary as it would be created when script terminates).IfNotExist, ahk_setting.ini{FileAppend,([function_call_order]function_number_1=1function_number_2=2function_number_3=3function_number_4=4), ahk_setting.ini}

; Read from INI file. May be solved by a for loop, but avoid this in example because function names may refer to a description of a image to match (own experience)IniRead, OutputVar, ahk_setting.ini, function_call_order, function_number_1,1table_functionsnames_sorted[1]:= OutputVar

F8::Loop,4; Same number as number of possible functions to call.{ func_index := table_functionsnames_sorted[A_Index] function_returned_value := funksjon_%func_index%()If(function_returned_value ==1){If(A_Index==1)Break; The first function in queue returned true, so no need to proceed nor do any sorting.Else{; Function returned true moves one step forward in queue. outOfArray_value := table_functionsnames_sorted[A_Index] table_functionsnames_sorted[A_Index]:= table_functionsnames_sorted[A_Index-1] table_functionsnames_sorted[A_Index-1]:= outOfArray_valueBreak; Do not call any more functions when one returns true.}}}

; Write to INI when exit.exitFunction(){Global table_functionsnames_sortedTrayTip, Exit script now, Writing the functions order to the INI file `n---------------`nReason for exit: %A_ExitReason%

For i , Value in table_functionsnames_sortedIniWrite,%Value%, ahk_setting.ini, function_call_order, function_number_%i%

IniWrite, %A_ExitReason%, ahk_setting.ini, function_call_order_other, exit_reasonSleep3000; only for traytip to stay long enough so user have time to read.}

; ----------------------- Functions that may or may not return true - dummy functions only suitable for this example.funksjon_1(){MsgBox, 0x124, Funksjon 1, Would you want function number 1 to returntrue??,4IfMsgBox YesReturn1Return0}

Almost_there wrote:Hi. I'm not where I talk so much about those tiny micro seconds one operator compares to another. Instead I focus on how to improve the kind of taksk that I know takes times, and how to make it as effective as possible.

#NoEnv; Recommended for performance and compatibility with future AutoHotkey releases.SendMode Input ; Recommended for new scripts due to its superior speed and reliability.SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.

/* Scripted by Grobe <smiley goes here>*/

; Writes function order to ini file, and display traytip to the user.; Gives errormessage when trying to launch same script twice - need to fix that.OnExit("script_terminates")

; I decided for using two separate arrays because it is easier for me (personally) to deal with.; Later on, I may change it to use a two-dimensional array instead.function_names_list :=Object()hitCounts :=[0,0,0,0]

F8::mainLoop:Loop,%number_of_functions_call%{ func_index := function_names_list[A_Index] function_return_value := funksjon_%func_index%()If(function_return_value ==1){If(A_Index==1){ hitCounts[1]++Break, mainLoop ; Function called was already first in queue and no sorting is required.}Else{; ACTION 1 - Poeng legges til hitCounts[A_Index]++ index_last_used_last :=A_Index-1; number of iterations used in bubble-sort (performance tweak - limits iterations).; Here I can allow making performance tweak for bubble-sort because the counts would never increase by more than 1 between each; time that sorting is performed.

; ACTION 2 - Sorting routine - Sorting based on hitCounts[], but the move of array elements is equal in both arrays.loop_search_all_decending:Loop,%index_last_used_last%{ index_less_than_next :=A_indexIf(hitCounts[A_Index+1]> hitCounts[A_Index]){; If one index found to have less counts than next, run bubble-sort. status_sorted_secondary :=0; If value is 1, the hitCounts[] is properly sorted (highest counts first)loop_sort_bubble:While, !status_sorted_secondary{loop_backwards:Loop,%index_less_than_next%{ status_sorted_secondary :=1 i_backwards := index_last_used_last -A_index+1; Searching backwards for entries that is not sorted. That normally requires less iterations.

If( hitCounts[i_backwards+1]> hitCounts[i_backwards]){ status_sorted_secondary :=0; Resets sorting status - this makes the while loop to iterate one more time (until sorted)

; TEST - display for the user that bubblesort actually works. Because of measurements that limits; the number of iterations for bubble-sort (we always know what index of function returns 1, and counts never increases more; than once per iteration of main loop) you should see this only once. arrayContentText1(hitCounts)

; Swap number in table index in function_names_list[] with the index above. rekkefolge_temp := function_names_list[i_backwards] function_names_list[i_backwards]:= function_names_list[i_backwards+1] function_names_list[i_backwards+1]:= rekkefolge_temp}}}; while "not sorted"}; If "next indeks have a higher number of counts"Else{; next one is already bigger - skip (this whole block can be deleted)Continue, loop_search_all_decending}}; main sorting loop

Break; Prevents the code to call more than one function.}; Check if the function called is already first in queue.}; if "return of called function is 1"}; Loop main - loops through a number of functions.

; Display the values in both arrays - that is function call order and the number of hits for each function callarrayContentText2(arrayID, counterArray){ textOut :="Index`t`tfunction_id`t`tCounts`n"For i , Value in arrayID textOut .= i ."`t-`t". Value ."`t-`t". counterArray[i]."`n"MsgBox,%textOut%}

For i , Value in function_names_listIniWrite,%Value%, ahk_setting.ini, function_call_order, rekkefolge_%i%

For i , Value in hitCounts{If(i ==1); for some rare reason, the IF statements fails when pharanteses is removed. counts := ValueElse counts .=" - ". Value}

; Writes some more information to the ini file. Not used later, just simple information.; Maybe add total number of counts in a later version.IniWrite,%counts%, ahk_setting.ini, function_call_order_other, function_call_counts_sortedIniWrite, %A_ExitReason%, ahk_setting.ini, function_call_order_other, exit_reasonSleep3000}

; ----------------------- The functions that is to be called - main code will try to call the functions in most effective order (most used function is tried first).funksjon_1(){MsgBox, 0x124, Funksjon 1, Do you want function number 1returntrue?`n ------ `n`nYou got 4 seconds to decide before I decide -NO- for you...,4IfMsgBox YesReturn1Return0}

E) Not sure about this one, but according to my testing: when working with large data sets and need to retrieve parts of the data fast, the fastest ways are: 1) create structured file with File.Write where each field is fixed size 4 or 8... bits. Then retrieve data using File.Reador 2) "FileRead + InStr()/SubStr()" - in cases where possible to use SubStr() instead of Loop,Parse These 2 methods are much faster than "Loop,Read" or "FileRead + Loop,Parse"

If you want more speed you need to change how you recognize buttons (basically stop using ImageSearch).Also the way you wrote that script is pretty cancerous.Rather than defining one function which let's you search for different Images at different positions you define like 8 functions and even worse rather than storing the results somewhere you let each function have them store it in static parameters.

@Almost_there"Gdip_ImageSearch" by MasterFocus is much faster than native "ImageSearch", - at least it used to be. I use it for reading text from screen.Althou your last post should probably be in a separate thread

serg wrote:@Almost_there"Gdip_ImageSearch" by MasterFocus is much faster than native "ImageSearch", - at least it used to be. I use it for reading text from screen.Althou your last post should probably be in a separate thread

I actually meant something completely different from ImageSearch.Maybe a Shape search algorythm.