Sign in to follow this  
Followers 0
BjornA

Speed of Simplesort

6 posts in this topic

Dear All,

The program below registers all files in the directory of "_New revised text" when this is on M: or N:. It then creates a database of the filenames and some other things and this works ok and is fairly fast.

When I try to sort the database it doesn't however. If I am using Listview / Simplesort for a short list it works ok, but when using it for a longer list (approx 300 rows with 5 columns) it sorts very slowly, it takes just under 10 seconds to sort it. Is this normal or am I missing something? (I have tried using Autohotkey for a similar task and it sorts it almost instantenously so apparently it can be done, but I would prefer using AutoIt)

; Script Start - Add your code below here
#include <GUIConstantsEx.au3>
#include <StructureConstants.au3>
#include <ListViewConstants.au3>
#include <WindowsConstants.au3>
#include <Constants.au3>
#include <GuiListView.au3>
#include <GuiButton.au3>
#include <Array.au3>

Opt('MustDeclareVars', 1)
global $aRec[1000][4]
global $hWin, $hList, $B_DESCENDING
global $CurrRec
global $hBtnAccess

CreateWin()
Getdata()
RunProgram()

;*******************************************************************************************
func GetData()
local $aAllDrives = DriveGetDrive("ALL")
Local $search, $MyDir, $MyFile, $Au, $Size, $FullName, $Access, $FirstPos
For $i = 1 to $aAllDrives[0]
  if StringInStr("M: N: ", $aAllDrives[$i])>0 then
   $search = FileFindFirstFile( $aAllDrives[$i] & "\*")
   if @error then exitloop
   while 1
    $MyDir = FileFindNextFile($search)
    if @error then exitloop
    if @extended=1 then  ; 1 = directory
     if $MyDir="_New revised text" then
      FileClose($search)
      $search=FileFindFirstFile( $aAllDrives[$i] &"\"& $MyDir & "\*.txt")
      while 1
       $MyFile=FileFindNextFile($search)
       if @error then exitloop
       $FirstPos=StringInStr( $MyFile,"- ")
       if $FirstPos>1 then
        $Au=StringMid($MyFile,$Firstpos+2)
        $Au=StringMid($Au,1,StringLen($Au)-4)
        $Size=int(FileGetSize($aAllDrives[$i] &"\"& $MyDir &"\"& $MyFile)/1024)
        $FullName=$aAllDrives[$i] &"\"& $MyDir &"\"& $MyFile
        $Access=FileGetTime($FullName, 0, 1)
        GUICtrlCreateListViewItem($Au&"|"&$MyFile&"|"&$Size&"|"&$FullName&"|"&$Access,$hList)
       endif
      wend
     endif
    endif
   wend
  endif
next
GUISetState()
Return
endfunc

func CreateWin()
MsgBox(1,"","createwin")
$hWin= GUICreate ( "Getting author name" , 500, 300, -1, -1, $WS_MINIMIZEBOX+$WS_SIZEBOX )
$hList=GUICtrlCreateListView ("Author name|File name|Size|Total name|Access", 10,10,480,250)
_GUICtrlListView_SetItemCount($hList, 1005)
_GUICtrlListView_SetColumnWidth($hList, 0, 130)
_GUICtrlListView_SetColumnWidth($hList, 1, 270)
_GUICtrlListView_SetColumnWidth($hList, 2, 50)
_GUICtrlListView_SetColumnWidth($hList, 3, 50)
_GUICtrlListView_SetColumnWidth($hList, 4, 100)
GUICtrlSetResizing($hList,$GUI_DOCKAUTO)
endfunc

func RunProgram()
Local $msg
Global $B_DESCENDING[_GUICtrlListView_GetColumnCount($hList)]
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
GuiSetState(@SW_SHOW)
while 1
  $msg=GUIGetMsg()
  if $msg = $GUI_EVENT_CLOSE Then ExitLoop
wend
GUIDELETE($hWin)
endfunc

Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)  ; someone else's code !
#forceref $hWnd, $iMsg, $iwParam
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndList, $tInfo
Local $selectedRow
$hWndList = $hList
    If Not IsHWnd($hList) Then $hWndList = GUICtrlGetHandle($hList)
    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    If ($hWndFrom = $hWndList) Then
  If ($iCode = $LVN_COLUMNCLICK) Then
   $tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam)
   _GUICtrlListView_SimpleSort($hWndList, $B_DESCENDING, DllStructGetData($tInfo, "SubItem"))
  ElseIf ($iCode = $NM_DBLCLK) Then
   $selectedRow = _GUICtrlListView_GetSelectionMark($hList)
   Run(@WindowsDir & "\notepad.exe " & _GUICtrlListView_GetItemText($hList, $selectedRow, 3), "")
  EndIf
EndIf
EndFunc

I would be grateful for any help

/ Björn

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

BjornA,

Welcome to the AutoIt forum. ;)

Using your code, I can SimpleSort 1340 files in about 4 secs - which is considerably faster than you are managing. But in either case, I would be very wary about spending so long in a message handler - when the Help file says:

"the return to the system should be as fast as possible !!!

it means it! :D

I have placed the sort outside the handler and that has dramatically improved the time taken - it now takes just over 2 secs to sort the same number of files. Look for the <<<<<<<<<<<<<<< lines - and you will have to change the drive and folder names back to match your system:

; Script Start - Add your code below here
#include <guiconstantsex.au3>
#include <structureconstants.au3>
#include <listviewconstants.au3>
#include <windowsconstants.au3>
#include <constants.au3>
#include <guilistview.au3>
#include <guibutton.au3>
#include <array.au3>

Opt('MustDeclareVars', 1)
Global $aRec[1000][4]
Global $hWin, $hList, $B_DESCENDING
Global $CurrRec
Global $hBtnAccess
Global $iSort = -1 ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

CreateWin()
Getdata()
RunProgram()

;*******************************************************************************************
Func GetData()
    Local $aAllDrives = DriveGetDrive("ALL")
    Local $search, $MyDir, $MyFile, $Au, $Size, $FullName, $Access, $FirstPos
    For $i = 1 To $aAllDrives[0]
        If StringInStr("M:", $aAllDrives[$i]) > 0 Then
            $search = FileFindFirstFile($aAllDrives[$i] & "*")
            If @error Then ExitLoop
            While 1
                $MyDir = FileFindNextFile($search)
                If @error Then ExitLoop
                If @extended = 1 Then ; 1 = directory
                    If $MyDir = "Music" Then ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
                        FileClose($search)
                        $search = FileFindFirstFile($aAllDrives[$i] & "" & $MyDir & "*.txt")
                        While 1
                            $MyFile = FileFindNextFile($search)
                            If @error Then ExitLoop
                            ;If $FirstPos > 1 Then  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
                                $Au = StringMid($MyFile, $FirstPos + 2)
                                $Au = StringMid($Au, 1, StringLen($Au) - 4)
                                $Size = Int(FileGetSize($aAllDrives[$i] & "" & $MyDir & "" & $MyFile) / 1024)
                                $FullName = $aAllDrives[$i] & "" & $MyDir & "" & $MyFile
                                $Access = FileGetTime($FullName, 0, 1)
                                GUICtrlCreateListViewItem($Au & "|" & $MyFile & "|" & $Size & "|" & $FullName & "|" & $Access, $hList)
                            ;EndIf  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
                        WEnd
                    EndIf
                EndIf
            WEnd
        EndIf
    Next
    GUISetState()
    Return
EndFunc   ;==>GetData

Func CreateWin()
    MsgBox(1, "", "createwin")
    $hWin = GUICreate("Getting author name", 500, 300, -1, -1, $WS_MINIMIZEBOX + $WS_SIZEBOX)
    $hList = GUICtrlCreateListView("Author name|File name|Size|Total name|Access", 10, 10, 480, 250)
    _GUICtrlListView_SetItemCount($hList, 1005)
    _GUICtrlListView_SetColumnWidth($hList, 0, 130)
    _GUICtrlListView_SetColumnWidth($hList, 1, 270)
    _GUICtrlListView_SetColumnWidth($hList, 2, 50)
    _GUICtrlListView_SetColumnWidth($hList, 3, 50)
    _GUICtrlListView_SetColumnWidth($hList, 4, 100)
    GUICtrlSetResizing($hList, $GUI_DOCKAUTO)
EndFunc   ;==>CreateWin

Func RunProgram()
    Local $msg
    Global $B_DESCENDING[_GUICtrlListView_GetColumnCount($hList)]
    GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
    GUISetState(@SW_SHOW)
    While 1
        $msg = GUIGetMsg()
        If $msg = $GUI_EVENT_CLOSE Then ExitLoop

        If $iSort > -1 Then ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
            Local $iBegin = TimerInit()
            _GUICtrlListView_SimpleSort($hList, $B_DESCENDING, $iSort)
            ConsoleWrite(TimerDiff($iBegin) & @CRLF)
            $iSort = -1
        EndIf ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    WEnd
    GUIDelete($hWin)
EndFunc   ;==>RunProgram

Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam) ; someone else's code !
    #forceref $hWnd, $iMsg, $iwParam
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndList, $tInfo
    Local $selectedRow
    $hWndList = $hList
    If Not IsHWnd($hList) Then $hWndList = GUICtrlGetHandle($hList)
    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    If ($hWndFrom = $hWndList) Then
        If ($iCode = $LVN_COLUMNCLICK) Then
            $tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam)
            $iSort = DllStructGetData($tInfo, "SubItem") ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
        ElseIf ($iCode = $NM_DBLCLK) Then
            $selectedRow = _GUICtrlListView_GetSelectionMark($hList)
            Run(@WindowsDir & "notepad.exe " & _GUICtrlListView_GetItemText($hList, $selectedRow, 3), "")
        EndIf
    EndIf
EndFunc   ;==>WM_NOTIFY

Any help? :)

M23

Edit: Just tried it with a mere 300 files and it sorts in less than a second. :D

Edited by Melba23
New data

Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites

Dear Melba23,

Thank you for the help, that is very good news. ;)

I'm not quite sure I understand why putting it outside the message handler improves the speed of the routine though. Do you know?

all the best / Björn

Share this post


Link to post
Share on other sites

BjornA,

I am afraid not. But keeping the script inside a message handler for a long period (I have found about 500ms to be a reasonable limit :)) is very likely to make the system unstable and crash. So perhaps the system was trying very hard not to crash during that very long wait of 10 secs and was taking cycles away from the sort algorithm. You will have to ask someone who understands the inner workings of Windows much better than I do to get a more concrete answer. ;)

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites

Thank you - I think I will just file it under "would be nice to know" instead of "need to know" ;)

Björn

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

I've always wondered why all the WM_NOTIFY examples (going way back) always include the following:

Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndList, $tInfo
$hWndList = $hList ; <-- reference to an external Control ID
If Not IsHWnd($hList) Then $hWndList = GUICtrlGetHandle($hList) ; <-- always true

$hList will be a Control ID throughout the program run, so assigning it to another variable, then testing if that is a handle, and then retrieving the actual handle and reassigning the variable seems a lot of extra gyrations, particularily since WM_NOTIFY is triggered a bazillion times by a number of internal Windows events.

I've been moving the ListView handle ($hWndList in this case) to be a global at the top of the script, calling the GUICtrlGetHandle() immediately after the GUICreateListView() and have yanked the 2nd and 3rd lines (above) out my WM_NOTIFY routines.

Has worked fine for me.

PS - Pardon me, BjornA, for inserting a marginally off-topic (but still related) post into your thread. Welcome to the forum!

Edited by Spiff59

Share this post


Link to post
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
Sign in to follow this  
Followers 0