Я провел исследование по этой теме, но до сих пор не до конца понимаю блоки async
и await
в C#, поскольку многие люди предлагают разные функции и подходы. Тем не менее, я не могу найти ничего близкого к моей цели.
Я работаю в Unity и хочу отправить несколько снимков экрана через сокет в другое приложение. Unity требует, чтобы снимок экрана был сделан основным потоком, поскольку он не является потокобезопасным. Дорогостоящей операцией является отправка кадра, которую, по моему мнению, лучше обрабатывать фоновым потоком. Это делается в цикле while(running)
.
Возможно, самый простой способ — просто создать новый поток и передать туда кадр для обработки, но я хотел знать, есть ли эффективный способ сделать это с помощью async Task
.
Сначала я попытался создать асинхронную задачу, но понял, что без await
код не будет параллельным. Проблема, с которой я столкнулся, заключается в том, что я не хочу, чтобы основной поток блокировался и не требовал каких-либо результатов от задачи для продолжения.
Это окончательный код, который я использую:
private static async Task sendSceenshot(PushSocket socket, byte[] frame)
{
await Task.Run(() => socket.TrySendFrame(frame));
}
private static void Screenshot()
{
while (isRunning)
{
yield return new WaitForSeconds(1f);
// Take the screenshot...
// [...]
// Send the frame in the background without blocking the main thread
sendSceenshot(screenSocketWide, currentFrame);
// Reset and prepare for next frame
// [...]
}
Вы это делаете "по запросу" или в каждом кадре (обновлении)? Существуют асинхронные операции с изображениями, но преимущества зависят от контекста; например ленивая загрузка. Возможно, вам придется стоять в очереди при других обстоятельствах.
@GerrySchmitz Мне нужно отправлять скриншот каждые полсекунды. Я делаю это с помощью корутины в Unity. Я пробовал использовать AsyncGPURead, но это не сработало должным образом :( Есть ли у вас какие-либо другие предложения?
Для этого вы можете просто использовать метод Task.Run()
. Он использует пул потоков за вас, поэтому вам не придется иметь дело с потоками вручную.
private static void Screenshot()
{
//set up socket and frame
//the key part
await Task.Run(() => socket.TrySendFrame(frame));
}
См. это, чтобы более глубоко понять различия между Thread и Task.
Я не уверен, что вы имели в виду под «это не завершает работу программы», не могли бы вы уточнить?
Хорошо, но действительно ли это асинхронно или основной поток должен ждать, пока задача будет выполнена, чтобы перейти к следующему кадру?
И функция должна быть определена как aync
, верно? Ошибка: оператор await можно использовать только внутри асинхронного метода. Рассмотрите возможность пометки этого метода модификатором async и изменения типа возвращаемого значения на Task.
он асинхронный, основной поток не должен ждать. Цитируя документы: «[Task.Run] ставит указанную работу в очередь для запуска в пуле потоков и возвращает прокси-сервер для задачи»
Да, так и должно быть async
, ведь только этих методов можно ожидать.
поскольку вы все равно не ожидаете выполнения функции, вы также можете опустить await
из Task.Run
.
К сожалению, я не вижу от этого какого-либо существенного улучшения производительности. FPS в игре по-прежнему очень низкий, поскольку их отправляют из основного потока. В любом случае спасибо!
с Unity я бы вообще рекомендовал UniTask , где вы просто используете .Forget(); чтобы позволить ему работать асинхронно... по крайней мере до тех пор, пока Awaitable не установится достаточно ;)