1

Тема: VBS: [псевдо]мультипоточность используя onreadystatechange ?

Приветствую господа. Вроде уже эту тему вертели как могли, так что если я брежу, удалим это к чёрту.

Ковыряясь с onreadystatechage задумался о запуске кода параллельно.

Скажите, кто-нибудь так экспериментировал ? При этом ведь деления на потоки не происходит и обратные вызовы WScript всё равно ставит в очередь ?


Option Explicit

Dim s
Dim n

RunThread GetRef("Test1")
RunThread GetRef("Test2")
RunThread GetRef("Test3")

MsgBox "Процедуры запущены !"

Do While n > 0
    WScript.Sleep 100
Loop

MsgBox s

Sub RunThread(oProc)
    Dim cThread
    Set cThread = New cThread
    cThread.Run oProc
    n = n + 1
End Sub

Sub Test1()
    WScript.Sleep 1000
    s = s & "Test1" & vbCrlf
    n = n - 1
End Sub

Sub Test2()
    WScript.Sleep 100
    s = s & "Test2" & vbCrlf
    n = n - 1
End Sub

Sub Test3()
    s = s & "Test3" & vbCrlf
    n = n - 1
End Sub

Class cThread
    Private oHR
    Private oCallback
    Private Sub Class_Initialize()
        Set oHR = CreateObject("MSXML2.XMLHTTP")
    End Sub
    
    Sub Run(oProc)
        Set oCallback = oProc
        oHR.onreadystatechange = Me
        oHR.Open "HEAD", "http://www.com", True
        oHR.send
    End Sub
    
    Public Default Sub oncallback()
        if oHR.readyState = 2 Then
            oCallback
        End if
    End Sub
End Class
Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

2

Re: VBS: [псевдо]мультипоточность используя onreadystatechange ?

Не до конца понимаю, что делает ваш код, поэтому выскажу только общие соображения. У движка VBS потоковая модель — both, т.е. теоретически позволяет и многопоточность, но WScript его использует в однопоточном режиме. К функциям прямые вызовы из других потоков не проходят, а возможны только через маршаллинг, а это значит — в виде оконных сообщений. Т.е. они поступают в очередь сообщений того потока, где создан объект движка, и выполняются один за другим.

В процессе выполнения одного вызова в него может вклиниться другой, т.к. при вызове WScript.Sleep, видимо, проверяется очередь сообщений, и если там есть вызов другой функции, то начнёт выполняться он, а первый будет его ждать.

По крайней мере к таким выводам я пришёл по результатам экспериментов.

3

Re: VBS: [псевдо]мультипоточность используя onreadystatechange ?

Ясно. Благодарю. Надо будет почитать про маршалинг.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

4

Re: VBS: [псевдо]мультипоточность используя onreadystatechange ?

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

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

Кстати, интереснейшая альтернатива функции GetRef() - использовать объект Me экземпляра класса с объявленным дефолтным методом. Этож получается можно организовать коллбэк не только глобально объявленных процедур и функций, но и методов экземпляров класса, к которым GetRef доступа не имеет?

Щт Уккщк Куыгьу Туче
’ҐЄгй п Є®¤®ў п бва Ёж : 1251

5

Re: VBS: [псевдо]мультипоточность используя onreadystatechange ?

omegastripes пишет:

Кстати, интереснейшая альтернатива функции GetRef() - использовать объект Me экземпляра класса с объявленным дефолтным методом. Этож получается можно организовать коллбэк не только глобально объявленных процедур и функций, но и методов экземпляров класса, к которым GetRef доступа не имеет?

Я думал никто не заметит ). Всё-таки "спалился". Хотя в JS это реализуется ещё симпатичнее. )

Изначально идея была в проверке проксилиста на предмет "живых" прокси. Вот я и задумался как прицепить к "безликому" вызову onreadystatechange связь с вызывающим объектом.


// Пустой лог
var sLog = ""

// Запускаем проверку прокси
checkProxy("64.14.41.42:80")
checkProxy("69.50.64.153:3128")
checkProxy("41.162.23.91:80")
checkProxy("211.103.210.38:8080")

// Ждём пока обработаются запросы
WScript.Sleep(1000);

WScript.Echo("Рабочие прокси сервера: \r\n\r\n" + sLog);

function checkProxy(proxy){
    // Создание нового объекта проверки прокси
    var oPC = new proxyChecker()
    // Передача адреса прокси объекту
    oPC.proxy = proxy
    // Запуск проверки прокси
    oPC.check(proxy_onresponse)
}

// Процедура обратного вызова для proxyChecker-ов
function proxy_onresponse(oPC) {
    sLog += oPC.proxy + "\r\n"
}

function proxyChecker() {
    // Переменная для хранения ссылки на функцию обратного вызова
    var callback;
    // Переменная для передачи ссылки на себя в callback
    var me = this;
    // Создание объекта для отправки HTTP запросов
    var oHR = new ActiveXObject("MSXML2.ServerXMLHTTP.6.0");
    // Установка URL по умолчанию для проверки запроса
    this.url = "http://www.com";

    // Установка обработчика состояний объекта запросов
    oHR.onreadystatechange = function(){
        // Если объект перешёл в состояние 2 - loading, значит ответ от прокси есть
        if (oHR.readyState == 2) {
            // Завершаем запрос
            oHR.abort();
            // Генерация события обратного вызова
            callback(me)
        }
    }

    // Функция отправки запроса для проверки прокси
    this.check = function(onresponse){
        // Сохранение ссылки на функцию обратного вызова
        callback = onresponse
        // Установка прокси сервера
        if (this.proxy == '') oHR.setProxy(2, this.proxy);
        // Инициализация запроса через прокси
        oHR.open("HEAD", this.url, true);
        // Отправка запроса
        oHR.send();
    }
}
Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !