Добрый день, Всем С момента появления VMLua в КВИКЕ неоднократно рассказывал о том, что применение event вместо sleep не только экономит ресурсы процессора, но и позволяет не пропускать события в колбеках и максимально бысто на них реагировать. говорил об этом например здесь: https://forum.quik.ru/forum17/topic8426/ --------------------- К сожалению, кроме бессмысленного хамства некоторых посетителей форума, ничего конкретного никто не написал. --------------- Но вот наконец-то появился вменяемый чел paluke . и после моей попытки в очередной раз объяснить преимущество event https://forum.quik.ru/messages/forum10/message75435/topic8600/#message75435
он все же решил проверить это и убедился, что это так действительно:
Код
Просто проверка концепции:
Кодw32 = require("w32")
run = true
evt = false
function OnInit()
evt = w32.CreateEvent(nil, 0, 0, nil)
end
function OnStop()
run = false
w32.SetEvent(evt)
end
function main()
while run do
w32.WaitForSingleObject(evt, 1000000)
end
w32.CloseHandle(evt)
end
В колбеках вызываете SetEvent - main сразу просыпается.
Присоединяюсь. Не нужно иметь много образования чтобы понять что техника с ожиданием событий эффективна. А реализация не так сложна, как кажется на первый взгляд.
Для моих целей сообщения тоже оказались заметно быстрее, чем sleep. На скрине для каждой пары неродных для квика стаканов левый отрисован с ожиданием через сообщения, правый - через sleep. Внизу стаканов статистика потерь, они на правых стаканах больше. Kernel time и cpu time тоже меньше на потоке, который ждёт событий. Поскольку рисование стаканов идёт в main скрипта, нельзя использовать WaitForMultipleObjects для событий из OnQuote и OnStop, нужно MsgWaitForMultipleObjectsEx, чтобы main включался на событиях GUI для стаканов. Её нет в w32, пришлось подключать через cffi-lua. Инструкция по сборке написана тут. Если сравнивать время исполнения между w32 и cffi-lua, то конечно же w32 быстрее (SetEvent на 12%, CreateEvent на 23%). Важные части кода:
Код
local w32 = require "w32-ext"
local ffi = require "cffi"
local SetEvent = w32.SetEvent
local MsgWaitForMultipleObjectsEx = w32.MsgWaitForMultipleObjectsEx
local cb_t = {'EDM4','SiM4','CRM4','CNYRUB_TOM'}
local e_quote, e_stop
local is_run = true
function OnQuote(class_code, sec_code)
local sent = cb_t[sec_code]
if sent then
cb_t[sec_code] = sent + 1
SetEvent(e_quote)
end
end
function OnStop()
is_run = false
SetEvent(e_stop)
end
function main()
e_stop = w32.CreateEvent(nil, 0, 0, nil)
e_quote = w32.CreateEvent(nil, 0, 0, nil)
local events = ffi.new("HANDLE[2]", {e_quote, e_stop})
local WAIT_TIMEOUT = w32.WAIT_TIMEOUT
while is_run do
local res = MsgWaitForMultipleObjectsEx(2, events, 500, 7423, 0) -- QS_ALLINPUT == 7423
if res == 1 then break end
if res == WAIT_TIMEOUT then
-- по таймауту обработать сообщения, например, о смене foreground окна
else
-- обновить стаканы
end
end
end
end
w32-ext.lua:
Код
local w32 = require("w32")
local ffi = require "cffi"
ffi.cdef [[
typedef unsigned int UINT;
typedef unsigned long DWORD;
typedef long long LRESULT;
typedef long long LPARAM;
typedef unsigned long long WPARAM;
//typedef void* HWND; // in windows
typedef intptr_t HWND; // uintptr_t not ok as it appends 'ULL', LPARAM also ok
typedef intptr_t HANDLE;
void SetLastError(DWORD);
//LRESULT SendMessageA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
HWND GetForegroundWindow();
DWORD MsgWaitForMultipleObjectsEx(DWORD nCount, const HANDLE *pHandles, DWORD dwMilliseconds, DWORD dwWakeMask, DWORD dwFlags);
]]
w32.SetLastError = ffi.C.SetLastError
w32.GetForegroundWindow = ffi.C.GetForegroundWindow
w32.MsgWaitForMultipleObjectsEx = ffi.C.MsgWaitForMultipleObjectsEx
-- those calls trigger 127 error on first invocation
w32.SetLastError(0)
return w32