1 (изменено: Евген, 2009-12-09 09:09:30)

Тема: VBScript / WSHController : Попытка асинхронного запуска

Хотя бы попытка была полунеудачная, так и не получилось сделать задуманное асинхронно, но хотя бы поппытка была, может у кого получилось более удачно, или дальше продвинулся в этом вопросе, с удовольствием пообщаюсь, а напока выкладываю свой вариант:
Предположение было следующее, Win32_PingStatus прекрасно работает асинхронно (раньше уже выясняли), дык вот с его помощью хотелось задать начальную асинхронность процессу, и уже в его асинхронных ответах (возвращающихся понгах - событие асинхронное) запускать нужную мне процедуру (в надежде что процесс дальше будет продолжаться асинхронно - многопоточно) , но процесс выстраивается в шеренгу по одному (как в магазине занимают очередь) и вся многопоточность и асинхронность на этом заканчивается

SN="SomeScript.vbs"
arrComputers = Array("strComp02","strComp03","strComp04","strComp05","strComp06","strComp07","strComp08","strComp09","strComp10","strComp11","strComp13","strComp14","strComp15","strComp16","strComp17","strComp18","strComp19","strComp20","strComp21","strComp22","strComp23","strComp24","strComp26","strComp27","strComp29")
Set objService = GetObject("winmgmts:\\.\Root\CIMV2")
Set objSink = WScript.CreateObject("WbemScripting.SWbemSink", "Sink_")
Set fso = CreateObject("Scripting.FileSystemObject")
Set file = fso.OpenTextFile("result.log", 8, True)
file.WriteLine String(28,"-") & " " & date & "  " & time & String(28,"-")
bdone = False
strCount=0

For Each strComputer In arrComputers
  Set objContext = CreateObject("WbemScripting.SWbemNamedValueSet")
  objContext.Add "hostname", strComputer
objService.ExecQueryAsync objSink, "select * from Win32_PingStatus where address ='" & strComputer & "'", , , , objContext
Next

While Not bdone

If strCount=ubound(arrComputers)+1 Then
bdone=True
file.Close
End If

WScript.Sleep 100

Wend

Sub Sink_OnObjectReady(objWbemObject, objWbemAsyncContext)
strCount=strCount+1
Set strComputer = objWbemAsyncContext.Item("hostname")
res=""
  Select Case objWbemObject.StatusCode
    Case 0
      res = "On"
    Case Else
      res = "Off"
  End Select
If res="On" Then       '1
Set oController = CreateObject("WSHController")
file.WriteLine strComputer & " - On"
On Error Resume Next
Set oProcess = oController.CreateScript(SN,strComputer)
oProcess.Execute
If Err.Number<>0 Then  '2
file.WriteLine strComputer & " - Connection Error !!!"
Err.Clear
On Error Goto 0
Else                   '2                  ' если нет ошибок при удалённом запуске
Do While oProcess.Status <> 2              ' ждём окончания удалённой работы скрипта
    WScript.Sleep 100
Loop
Set oController = Nothing
file.WriteLine strComputer & " - Sucessfull !!!" & Now
End If                 '2

Else                   '1                  ' не отвечает на пинг 
file.WriteLine strComputer & " - Off"
End If                 '1
End Sub
Времени не хватает... :-(

2

Re: VBScript / WSHController : Попытка асинхронного запуска

Евген, он и выполняется асинхронно, вот только Вы тормозите работу текущего скрипта в процедуре посредством:

Do While oProcess.Status <> 2              ' ждём окончания удалённой работы скрипта
    WScript.Sleep 100
Loop

Так что, тут ничего удивительного.

3

Re: VBScript / WSHController : Попытка асинхронного запуска

С одним скриптом всё работает без проблем.

C:\Песочница\41\SimpleSleep3000.vbs:

WScript.Sleep 3000

Сам скрипт:

Option Explicit

Dim arrComputers
Dim objWshController, objWshRemote
Dim boolDone

boolDone = False

Set objWshController = WScript.CreateObject("WSHController")
Set objWshRemote     = objWshController.CreateScript("C:\Песочница\41\SimpleSleep3000.vbs", "localhost")

WScript.ConnectObject objWshRemote, "WshRemote_"
objWshRemote.Execute

Do
    WScript.Sleep 100
Loop Until boolDone

WScript.DisconnectObject objWshRemote

Set objWshRemote     = Nothing
Set objWshController = Nothing

WScript.Quit 0
'=============================================================================

'=============================================================================
Sub WshRemote_Start
    WScript.Echo "> Script start"
End Sub
'=============================================================================

'=============================================================================
Sub WshRemote_End
    WScript.Echo "< Script end"
    boolDone = True
End Sub
'=============================================================================

Переменные создаются, участвуют в работе, очищаются.

> Script start
< Script end

4

Re: VBScript / WSHController : Попытка асинхронного запуска

При попытке использовать более одного запущенного экземпляра скрипта начинаются проблемы, которые, отчасти, можно, хоть и через @@@@, но обойти.

Option Explicit

Dim arrComputers, elem
Dim objWshController, objWshRemote
Dim dictWshRemotes
Dim boolDone, lngCount

arrComputers = Array("Machine01", "Machine02", "Machine03", "Machine04", "Machine05")

boolDone = False
lngCount = 0

Set objWshController = WScript.CreateObject("WSHController")
Set dictWshRemotes   = WScript.CreateObject("Scripting.Dictionary")

For Each elem In arrComputers
    WScript.Echo elem
    dictWshRemotes.Add elem, objWshController.CreateScript("C:\Песочница\41\SimpleSleep3000.vbs", elem)
    WScript.ConnectObject dictWshRemotes.Item(elem), "WshRemote_"
    
    lngCount = lngCount + 1
    
    dictWshRemotes.Item(elem).Execute
Next

Do
    WScript.Sleep 100
Loop Until boolDone

For Each elem In arrComputers
    WScript.Echo elem
    WScript.DisconnectObject dictWshRemotes.Item(elem)
    Set dictWshRemotes.Item(elem) = Nothing
    dictWshRemotes.Remove elem
Next

Set dictWshRemotes   = Nothing
Set objWshController = Nothing

WScript.Quit 0
'=============================================================================

'=============================================================================
Sub WshRemote_Start
    WScript.Echo "> Script start"
End Sub
'=============================================================================

'=============================================================================
Sub WshRemote_End
    WScript.Echo "< Script end"
    
    lngCount = lngCount - 1
    
    If lngCount = 0 Then
        boolDone = True
    End If
End Sub
'=============================================================================

Создаём словарь, проходим по списку машин, добавляем объектную переменную в словарь, наращиваем счётчик, запускаем на исполнение. В событии останова уменьшаем счётчик, пока он не станет равным нулю. После завершения всех заданий пробегаемся по словарю, отстыковываемся от событий объектов, очищаем ссылки, очищаем словарь.

Machine01
Machine02
> Script start
Machine03
> Script start
Machine04
> Script start
Machine05
> Script start
> Script start
< Script end
< Script end
< Script end
< Script end
< Script end
Machine01
Machine02
Machine03
Machine04
Machine05

Где здесь главная проблема? Главная проблема в том, что внутри процедуры обработки события «WshRemote_End» мы никак не можем гарантированно определить, от какого именно объекта WshRemote'а пришло это событие — для этого нет ровным счётом никаких данных. Можно, казалось бы, попытаться перебрать словарь и определить по статусу (WshRemote.Status = WshFinished) от какого именно объекта «WshRemote» пришло событие завершения, отстыковаться от него, очистить объектную переменную и удалить её из словаря. Но суть в том, что велика вероятность того, что, пока мы будем делать этот перебор, в этот промежуток времени завершится ещё одно или более заданий, т.е. окажется, что сразу несколько «WshRemote» из словаря будут иметь .Status = WshFinished. И всё, приплыли — мы опять застряли как буриданов осёл.

Для приведённого кода проблемы, изложенной в предыдущем абзаце не существует, поскольку тут нет понятия длины очереди (идея, за которую я ратовал в развитие Вашего примера: VBScript: асинхронная обработка множественных запросов WMI, а коллега mozers реализовал). В принципе, можно ограниченно работать и с длиной очереди — подобно вышеприведённому коду, то есть, задали длину очереди, наполнили очередь и ждём, пока она не станет равной 0 (напомню, что в VBScript: асинхронная обработка множественных запросов WMI поддерживается постоянная длина очереди, как только закончился один запрос в очереди — сразу создаётся новый), потом очищаем, наполняем очередь новой порцией запросов и т.д.

Чем мне не нравится этот подход? Казалось бы, то же самое… Ан нет: хоть сие и даёт более-менее квазипараллельную обработку, но стоит одному единственному запросу «заткнуться» на чём-нибудь надолго — и он «заморозит» всю обработку.

5

Re: VBScript / WSHController : Попытка асинхронного запуска

Мда....   тоже тупиково...   щас бы с Ken-ом Mayer-ом кофеёк погонять, мыслишками раскинуть...

Времени не хватает... :-(