Потоки LUA

invilso.

Известный
Автор темы
259
89
Версия MoonLoader
.027.0-preview
Привет, как можно исправить/изменить этот код чтобы он не стопил игру?
Или в луа невозможно созать полностью независимые потоки?
Может быть можно создать как-то мультипроцессинг?
lua_thread также стопит игру, хоть и ответ от сервера у меня занимает максимум 5мс, оно ощутимо подторможивает игру в эти моменты.

Lua:
local copas = require 'copas'

function send_command(route, command, server_host, server_port, callback)
    if not copas.running then
        copas.running = true
        lua_thread.create(function()
            wait(0)
            if not pcall(thread_manage_tool) then
                print('Copas err')
            end
        end)
    end
    copas.addthread(function()
        local udp = socket.udp()
        udp:setpeername(server_host, server_port)
        udp:send(route..";;;"..command)
        udp:settimeout(1)
        local response, err = udp:receive()
        udp:close()
        callback(response, err)
    end)
end

function thread_manage_tool()
    while not copas.finished() do
        local ok, err = copas.step(0)
        if ok == nil then error(err) end
        wait(0)
    end
    copas.running = false
end

P.S. Также попробовал реализовать на effil, никакого эффекта не дало. Я что-то не так делаю?
Lua:
function send_command(route, command, server_host, server_port, callback)
   local request_thread = effil.thread(function (route, command, server_host, server_port)
      local udp = socket.udp()
      udp:setpeername(server_host, server_port)
      udp:send(route..";;;"..command)
      udp:settimeout(1)
      local response, err = udp:receive()
      return true, response
   end)(route, command, server_host, server_port)
   -- If the query without response and error handling functions.
   if not callback then callback = function() end end
   -- Checking the execution of a thread
   lua_thread.create(function()
      local runner = request_thread
      while true do
         local status, err = runner:status()
         if not err then
            if status == 'completed' then
               local result, response = runner:get()
               if result then
                  resolve(response)
               end
               return
            end
         end
         wait(0)
      end
   end)
end
 
Последнее редактирование:
Решение
Через луа потоки? Которые coroutine, как описано на сайте lua.org? Это единственный вариант который я ещё не попробовал.

Просто блокируется игра вызовом функции connect:receive() и выставление таймаута не влияет, хотя в документации написано что должно влиять
Да нет же. Обычные потоки. Вот прекрасно работает udp запрос без зависаний. Ты что-то очень сильно всё переусложняешь лишними библиотеками. Такое ощущение у тебя проблема не в самих потоках

Lua:
local socket = require 'socket'

lua_thread.create(function()
    local ip, port = sampGetCurrentServerAddress()
    print(ip, port)
    while true do
        wait(0)
        local info = serverInfo(ip, port)
        if info then
            print(os.clock(), info.password...

Tema05

Известный
1,474
439
Привет, как можно исправить/изменить этот код чтобы он не стопил игру?
Или в луа невозможно созать полностью независимые потоки?
Может быть можно создать как-то мультипроцессинг?
lua_thread также стопит игру, хоть и ответ от сервера у меня занимает максимум 5мс, оно ощутимо подторможивает игру в эти моменты.

Lua:
local copas = require 'copas'

function send_command(route, command, server_host, server_port, callback)
    if not copas.running then
        copas.running = true
        lua_thread.create(function()
            wait(0)
            if not pcall(thread_manage_tool) then
                print('Copas err')
            end
        end)
    end
    copas.addthread(function()
        local udp = socket.udp()
        udp:setpeername(server_host, server_port)
        udp:send(route..";;;"..command)
        udp:settimeout(1)
        local response, err = udp:receive()
        udp:close()
        callback(response, err)
    end)
end

function thread_manage_tool()
    while not copas.finished() do
        local ok, err = copas.step(0)
        if ok == nil then error(err) end
        wait(0)
    end
    copas.running = false
end

P.S. Также попробовал реализовать на effil, никакого эффекта не дало. Я что-то не так делаю?
Lua:
function send_command(route, command, server_host, server_port, callback)
   local request_thread = effil.thread(function (route, command, server_host, server_port)
      local udp = socket.udp()
      udp:setpeername(server_host, server_port)
      udp:send(route..";;;"..command)
      udp:settimeout(1)
      local response, err = udp:receive()
      return true, response
   end)(route, command, server_host, server_port)
   -- If the query without response and error handling functions.
   if not callback then callback = function() end end
   -- Checking the execution of a thread
   lua_thread.create(function()
      local runner = request_thread
      while true do
         local status, err = runner:status()
         if not err then
            if status == 'completed' then
               local result, response = runner:get()
               if result then
                  resolve(response)
               end
               return
            end
         end
         wait(0)
      end
   end)
end
А зачем тебе copas или упаси господь effil если ты всё равно прокидываешь udp запрос через socket? Он спокойно работает в потоке lua_thread не влияя на игру. Лично у меня если не брать https запросы все потребности закрывают дефолтные потоки. Если у тебя другой случай возможно неправильно используешь библиотеку и на самом деле не через неё запрос делаешь
 
Последнее редактирование:
  • Нравится
Реакции: invilso.

invilso.

Известный
Автор темы
259
89
А зачем тебе copas или упаси господь effil если ты всё равно прокидываешь udp запрос через socket? Он спокойно работает в потоке lua_thread не влияя на игру. Лично у меня если не брать https запросы все потребности закрывают дефолтные потоки. Если у тебя другой случай возможно неправильно используешь библиотеку и на самом деле не через неё запрос делаешь
Через луа потоки? Которые coroutine, как описано на сайте lua.org? Это единственный вариант который я ещё не попробовал.

Просто блокируется игра вызовом функции connect:receive() и выставление таймаута не влияет, хотя в документации написано что должно влиять
 

Tema05

Известный
1,474
439
Через луа потоки? Которые coroutine, как описано на сайте lua.org? Это единственный вариант который я ещё не попробовал.

Просто блокируется игра вызовом функции connect:receive() и выставление таймаута не влияет, хотя в документации написано что должно влиять
Да нет же. Обычные потоки. Вот прекрасно работает udp запрос без зависаний. Ты что-то очень сильно всё переусложняешь лишними библиотеками. Такое ощущение у тебя проблема не в самих потоках

Lua:
local socket = require 'socket'

lua_thread.create(function()
    local ip, port = sampGetCurrentServerAddress()
    print(ip, port)
    while true do
        wait(0)
        local info = serverInfo(ip, port)
        if info then
            print(os.clock(), info.password, info.online, info.hostname)
            if not info.password or info.online > 0 then
                break
            end
        else
            print(os.clock(), 'info error')
        end
    end
end)

function serverInfo(ip, port)
    local info, data
    local s = socket.udp()
    s:setpeername(ip, port)
    s:settimeout(0)
    s:send(('SAMP%sai'):format(string.char(ip:match('(%d+)%.(%d+)%.(%d+)%.(%d+)'))))
    local timeout = os.clock() + 3
    while data == nil and os.clock() < timeout do
        wait(0)
        data = s:receive()
    end
    if data and data:len() > 11 and data:sub(1, 4) == 'SAMP' then
        info = {
            password = (data:byte(12) ~= 0),
            online = data:byte(13) + data:byte(14) * 256,
            hostname = data:sub(21, 20 + data:byte(17, 20) % 128)
        }
    end
    s:close()
    return info
end
 
Последнее редактирование:
  • Нравится
Реакции: invilso.

invilso.

Известный
Автор темы
259
89
Да нет же. Обычные потоки. Вот прекрасно работает udp запрос без зависаний. Ты что-то очень сильно всё переусложняешь лишними библиотеками. Такое ощущение у тебя проблема не в самих потоках

Lua:
local socket = require 'socket'

lua_thread.create(function()
    local ip, port = sampGetCurrentServerAddress()
    print(ip, port)
    while true do
        wait(0)
        local info = serverInfo(ip, port)
        if info then
            print(os.clock(), info.password, info.online, info.hostname)
            if not info.password or info.online > 0 then
                break
            end
        else
            print(os.clock(), 'info error')
        end
    end
end)

function serverInfo(ip, port)
    local info, data
    local s = socket.udp()
    s:setpeername(ip, port)
    s:settimeout(0)
    s:send(('SAMP%sai'):format(string.char(ip:match('(%d+)%.(%d+)%.(%d+)%.(%d+)'))))
    local timeout = os.clock() + 3
    while data == nil and os.clock() < timeout do
        wait(0)
        data = s:receive()
    end
    if data and data:len() > 11 and data:sub(1, 4) == 'SAMP' then
        info = {
            password = (data:byte(12) ~= 0),
            online = data:byte(13) + data:byte(14) * 256,
            hostname = data:sub(21, 20 + data:byte(17, 20) % 128)
        }
    end
    s:close()
    return info
end
Дааа, твой вариант отлично сработал, я переусложнял ужасно всё, из-за того что тупенький чутка и получал connect:receive без while.
Спасибо :)
Сделал также как и у тебя и всё прекрасно отрабатывает :)
Кстати, http запросы тоже скорее всего так можно делать, просто пишешь GET /route/ HTTP1.0 (как-то так) в connect:send, ну и конект нужно делать соответственно на 80 порт.
Lua:
function send_command(route, command, server_host, server_port, handler)
    local udp = socket.udp()
    udp:setpeername(server_host, server_port)
    udp:send(route..";;;"..command)
    udp:settimeout(0)
    local timeout = os.clock() + 3
    local response = nil
    while response == nil and os.clock() < timeout do
        wait(0)
        response = udp:receive(1024)
    end
    udp:close()
    handler(response)
end