Jump to content

Recommended Posts

Posted

Hi, I'm working on a script that closes running processes. The problem I'm having is that it consumes CPU resources.
I've tried changing sleep(10) to sleep(5000), and the CPU usage does indeed decrease, but it takes a while to close the process. What do you think I could do?

if there is another way to do it

I appreciate your help.

This is the code I'm working on:

#include <MsgBoxConstants.au3>
#include <GUIConstants.au3>
#include <File.au3>

HotKeySet("{9}", "goout")



While 1

Sleep (10)

    Local $aArray = FileReadToArray(@ScriptDir & "\test.dat")

    Local $iLineCount = @extended


For $i = 0 To $iLineCount - 1

    If ProcessExists($aArray[$i]) Then

    ProcessClose($aArray[$i])

    EndIf


Next

Wend


Func goout()

    Exit
EndFunc   ;==>Terminate

This is what I have inside test.dat as an example:test.dat

notepad.exe
notepad.exe
notepad.exe
notepad.exe
notepad.exe
notepad.exe
notepad.exe
notepad.exe
notepad.exe
notepad.exe
notepad.exe
notepad.exe
notepad.exe
notepad.exe
notepad.exe
notepad.exe
notepad.exe
notepad.exe
notepad.exe
notepad.exe

 

Posted
#include <MsgBoxConstants.au3>
#include <GUIConstants.au3>
#include <File.au3>

HotKeySet("{9}", "goout")

Local $sTestData

While 1
    Local $sTestNewData = FileRead(@ScriptDir & "\test.dat")
    If $sTestData <> $sTestNewData Then
        $sTestData = $sTestNewData
        Local $aData = StringSplit($sTestData, @CRLF, 1)
        For $i = 0 To $aData[0]
            If ProcessExists($aData[$i]) Then ConsoleWrite($aData[$i] & " ProcessClose: " & ProcessClose($aData[$i]) & @CRLF)
        Next
    EndIf
    Sleep(50)
WEnd

Func goout()
    Exit
EndFunc   ;==>goout

 

I know that I know nothing

Posted
1 hour ago, angel83 said:

What do you think I could do?

Describe what the real end goal is.
For an outside observer, this raises a few questions:

  • Why do you need a file with process names?
  • Why do you keep re-reading the file? - Does the file change during script execution? If so, are only new lines added, or is anything deleted?
  • Why do the process names appear multiple times in the file?
  • Do you only need to react when the file is changed, or permanently?

Once the real goal is known, you can optimize in a completely different way. (Keep the >x-y problem< in mind here)

 

Posted

First of all, thank you for responding.

 

Thanks AspirinJunkie . I don't think I gave too much information. Here are the answers to your questions.

Why do you need a file with process names? = Because another script added them to the test.dat file.

 

Why do you keep rereading the file? - Does the file change during script execution? If so, are new lines added or removed? = The test.dat file contains the names of the executables I want to close.

 

Why do process names appear multiple times in the file? = This was just an example, as names can be different, for example:

chrome.exe

photoshop.exe

GIMP.exe

CCleaner.exe

Visual Studio .exe

 

Do you only need to react when the file is changed, or permanently?

The executable names will be permanently stored in the test.dat file, so the process can close them.

 

Posted
24 minutes ago, angel83 said:

The test.dat file contains the names of the

[...]

The executable names will be permanently stored in the test.dat file, so the process can close them.

So that means the file doesn't change during script execution?
Then you don't need to read it in over and over again, just once: before the while loop. That should largely solve your performance issues.
But change your sleep to a higher value to reduce the load on the CPU (e.g., 250 or something like that).

Posted

If you need to read it repeatedly, AspirinJunkie should always have the script running. This way, when you run any program name from the test.dat list, it will exit immediately. The script I posted in the thread does this, but it consumes CPU.

Posted (edited)

It may be due to my limited understanding of English, but so far I have still not been able to find out whether the content of the file “test.dat” changes during the script runtime.
When I asked about this, the only answer I got was: “The information is in the file” – but that wasn't the question. The question was whether the content changes during the script runtime.
When I asked again, I was told that the script is supposed to run continuously – but that was not the answer to my question either.

But that is the crucial point!
To understand what is consuming so much CPU power, here is an explanation of what the script does with the permanent FileReadToArray:

  • The file is opened
  • The file is read in its entirety
  • The contents of the file are interpreted as a 1D array, converted into such a data structure, and stored in memory
  • The file is closed again.

And this happens every single time FileReadToArray is called. Over and over again. Every 10 ms! That's up to 100 times per second! (minus the runtime of the rest of the code in the loop)
The CPU has no choice but to work continuously.

However, this script structure only makes sense if the information in the file changes between loop iterations. Otherwise, the array is already stored in memory and does not need to be recreated each time.

Therefore, I am asking one last time for an answer to the question: Does the content of the file test.dat change during the runtime of the script?
Depending on the answer, there are various approaches to avoid constant reading from the hard disk—which is where the majority of CPU time is spent.

Edited by AspirinJunkie
Posted

Hello AspirinJunkie, sorry for taking so long to answer your question.
Does the contents of the test.dat file change during script execution? My answer is: NO.
Nothing changes during script execution. The test.dat file

 

AspirinJunkie, you're not the only one. I'm not perfect at English either. Spanish is my strongest language. Sometimes I have to use a translator. Just letting you know.

But I try to continue learning English as much as learning AutoIT programming.

have a nice day or good night.

Posted
3 hours ago, angel83 said:

Does the contents of the test.dat file change during script execution? My answer is: NO.

Then, as already mentioned, the most relevant starting point for reducing the load is to write FileReadToArray before the while loop – not within!
And at the same time, increase the sleep time slightly.
That alone should make a big difference.

If there is still a need for further optimization, then a different approach would be required:
Currently, your script queries the current status of the process list at regular intervals and processes it. This is commonly referred to as "polling".

A better option would be to tell Windows: You know when new processes are created anyway, so just let me know when that happens.
This way, the script can go to sleep and will be actively woken up by Windows when a new process appears. This approach is called event registration, for example.

There are events for file system operations or window creation and so on.
However, I am not aware of any event-based approach for process creation that does not require administrator privileges.
But we can still find a workaround.
WMI offers the option of periodically querying its tables internally and automatically reporting new records when changes are made.
Technically speaking, this is still polling, but in WMI it is more cost-effective than implementing it directly in AutoIt.

In addition, you can also specify which processes you are interested in and specify from the outset that only processes with a name from your list should be reported, e.g.
This further reduces the effort required for the script.

And yes, your concern is correct: this does make the script more complicated. But if further optimization is really necessary, there is no real way around it:

HotKeySet("{F9}", "goout")

; Create WMI object and sink for events
Global $oWMI  = ObjGet("winmgmts:\\")
Global $oSink = ObjCreate("WbemScripting.SWbemSink")

; say WMI that the script should be informed of new processes as they appear in test.dat. (See function definition)
_registerProcessCreation()

; endless loop for keeping the script running
Do              
    Sleep(100)
Until False

; Function that is automatically called when the __InstanceCreationEvent occurs
Func SINK_OnObjectReady($oProcess)
    ProcessClose($oProcess.TargetInstance.ProcessID)
EndFunc


Func goout()
    Exit
EndFunc

; Creates the query string that defines exactly which process settings should be responded to.
; This query is then linked to the user's own function as an event handler.
Func _registerProcessCreation()
    Local $mProcNames[]

    ; build the query-string out of the "Test.dat" file
    ; Queries the __InstanceCreationEvent events on the WMI class Win32_Process every 100 ms.
    ; Also limit the query to the processes listed in Test.dat.
    Local $sQuery = "SELECT * FROM __InstanceCreationEvent WITHIN 0.1 WHERE TargetInstance ISA 'Win32_Process' AND ("
    For $sProcessName In FileReadToArray("Test.dat")
        If Not MapExists($mProcNames, $sProcessName) Then ; Prevent duplicate process names
            $sQuery &= "TargetInstance.name = '" & $sProcessName & "' OR "
            $mProcNames[$sProcessName] = ""
        EndIf
    Next
    $sQuery = StringTrimRight($sQuery, 4) & ")"

    ; Events with the prefix “SINK_” are linked to corresponding AutoIt functions (we only need SINK_OnObjectReady).
    ObjEvent($oSink, "SINK_")

    ; Queries the __InstanceCreationEvent events on the WMI class Win32_Process every 100 ms.
    $oWMI.ExecNotificationQueryAsync($oSink, $sQuery)
EndFunc

 

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
  • Recently Browsing   0 members

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