Либо async void. Про блокирующие вызовы и так понятно - это не про UI. Но у Task.Run есть свои проблемы, которые как раз "решает" async void.
В async void асинхронные вызовы сохраняют контекст синхронизации, так что тебе в итоге требуется оборачивать в Task.Run только тяжёлые куски с вычислениями. В случае Task.Run, чтобы поменять что-то в VM или UI напрямую, придётся извращаться Dispatcher.Invoke - втыкать этот вызов где попадётся.
А на практике именно так и будет: ты делаешь Task.Run, а потом начинаешь ловить "миллион" ошибок о недопустимом потоке. Начинаешь втыкать Dispatcher.Invoke и потом напарываешься на рассинхрон в UI из-за того, что два свойства в двух разных Invoke поменялись. Или того хуже: тормоза анимации. В общем, в WPF я этого наелся в своё время, так что на желание запустить Task.Run сразу при нажатии кнопки, смотрю с некоторым отвращением =/
Неудачный пример. fire-and-forget в UI в нормальных прогах - редкость. Чаще всего требуется обратная связь. Хотя бы банальное: заблочить кнопку перед вызовом фоновой задачи и разблочить после.
Честно говоря не понял: "создавать более понятные и вызывающие больше доверия интерфейсы". Почему кнопка обернутая в новый usermedia станет понятнее и доверительнее, той же кнопки, но с колбеком, где права запросят?
AvaloniaUİ мне доже понравилась, только вот до сих пор непонятно насколько оно хорошо будет работать на мобильных устройствах...
Будет работать нормально. Написать нетребовательное к красоте приложение можно. Но если хочется что-то "красивое" для широкого пользователя, то уже есть проблемы.
Всё те же болячки от WPF: анимации и скролл в UI потоке. Из-за этого в процессе разработки начнёшь сталкиваться то тут, то там с подтормаживаниями интерфейса. Типа пара кадров в какой-нибудь анимации будут пропадать (это заметно, да) или при скролле будут подлагивания. В общем, пока ещё есть куда стремится. В этом плане MAUI выглядит привлекательнее, хотя он и ограничен платформами.
Вся соль в слайсах. Так можно передавать часть массива и работать в функции с ним, как цельным. Т.е. функции типа Func(byte[] buffer, int offset, int length) можно просто превратить в Func(Span<byte> buffer).
Ну и главное, что Span - это не только управляемый массив, за ним может быть и неуправляемая память. Соответственно тебе достаточно будет написать одну функцию с реализацией для Span, вместо отдельных реализаций для byte[] и byte*. Хотя реализация в таком случае обычно сводятся к unsafe с fixed массива, но со Span можно писать safe реализацию, что тоже плюсом.
Если архитектура проекта продуманная, модули изолированные, api / форматы данных документированные, модули делают понятные и без тз вещи, но тем не менее тз тоже есть, и задачи изолированные
Ну т.е. останется как раз та самая "примитивная фигня", с которой и нейронка справится? Об этом и речь.
В таком случае нужно не нейронкой восхищаться, а собой, раз сумел создать такую крутую архитектуру.
Ох ёёё... получается теперь в using EnterScope можно будет свободно await вызвать и компилятор слова не скажет. Прям замечательный выстрел в ногу будет для новичков (и не только).
Загуглите LimitedConcurrencyLevelTaskScheduler - это стандартная реализация от майков (в общем коде правда её нет). Ставите 1 поток и можно запускать в нем стандартные Task'и, которые так же будут друг за другом выполняться в пуле.
Что-то мне кажется, что не прокатит такая задумка. Проблема в том, что нельзя однозначно сказать, кто будет тем самым "предъявителем". К примеру, у вас есть контроллер, который запрашивает ISomeService и IControllerDependService, при этом ISomeService так же запрашивает IControllerDependService. Как вы будете резолвить нужный вашему контроллеру IControllerDependService, если первым его запросит ISomeService?
То, что вам нужно, это скорее возможность создавать дочерние провайдеры с заменой сервисов. И по идее можно реализовать собственный IControllerActivator, где как раз и делать подмену в зависимости от типа контроллера.
Тут точно не скажешь. Эта виндовая служба любит отжирать под 80-100% от свободного места в оперативке под кэш (у меня прям сейчас 18 из 20Гб свободного съело). Правда, что оно туда кладёт - фиг его знает.
Если сортировка строк подразумевает именно сортировку по коду каждого символа, то вроде как UTF-8 можно напрямую как массив байт сортировать - выйдет то же самое. Так можно избавится от лишних преобразований в string.
А про какую плотную интеграцию речь-то? Судя по примеру, просто добавили профиль публикации (PublishProfile, см. pubxml). Это по сути кастомный набор правил и команд для сборки и dotnet publish знать не знает, что этот DefaultContainer делает.
Проблема не в щелочной батарейке, а в литий ионном аккумуляторе.
Я вот сразу обратил внимание на слишком высокие показатели удельной ёмкости по объёму — 900 Вт*ч/л. У меня в голове всегда висела цифра 400. Сейчас специально проверил и действительно, многие источники про литий ион говорят до 600, ну максимум 700 Вт*ч/л в лабораторных условиях. Проверил по источнику, который вы ниже дали, там около этой цифры есть указатель на источник, но ссылки в статье нет. Да и переход на первоисточник этого источника не дал результата.
Откуда взяли эту цифры (900) я честно говоря не могу понять. Если цифра реальная, то это же должно быть прорывом в мировом масштабе.
Либо async void. Про блокирующие вызовы и так понятно - это не про UI. Но у Task.Run есть свои проблемы, которые как раз "решает" async void.
В async void асинхронные вызовы сохраняют контекст синхронизации, так что тебе в итоге требуется оборачивать в Task.Run только тяжёлые куски с вычислениями.
В случае Task.Run, чтобы поменять что-то в VM или UI напрямую, придётся извращаться Dispatcher.Invoke - втыкать этот вызов где попадётся.
А на практике именно так и будет: ты делаешь Task.Run, а потом начинаешь ловить "миллион" ошибок о недопустимом потоке. Начинаешь втыкать Dispatcher.Invoke и потом напарываешься на рассинхрон в UI из-за того, что два свойства в двух разных Invoke поменялись. Или того хуже: тормоза анимации.
В общем, в WPF я этого наелся в своё время, так что на желание запустить Task.Run сразу при нажатии кнопки, смотрю с некоторым отвращением =/
Неудачный пример. fire-and-forget в UI в нормальных прогах - редкость. Чаще всего требуется обратная связь. Хотя бы банальное: заблочить кнопку перед вызовом фоновой задачи и разблочить после.
Честно говоря не понял: "создавать более понятные и вызывающие больше доверия интерфейсы". Почему кнопка обернутая в новый usermedia станет понятнее и доверительнее, той же кнопки, но с колбеком, где права запросят?
Обратная совместимость разве не сохранится?
Будет работать нормально. Написать нетребовательное к красоте приложение можно. Но если хочется что-то "красивое" для широкого пользователя, то уже есть проблемы.
Всё те же болячки от WPF: анимации и скролл в UI потоке. Из-за этого в процессе разработки начнёшь сталкиваться то тут, то там с подтормаживаниями интерфейса. Типа пара кадров в какой-нибудь анимации будут пропадать (это заметно, да) или при скролле будут подлагивания. В общем, пока ещё есть куда стремится. В этом плане MAUI выглядит привлекательнее, хотя он и ограничен платформами.
В начале не хватает ещё одного пункта про циклические зависимости. Lazy эту проблему так же решает.
Вся соль в слайсах. Так можно передавать часть массива и работать в функции с ним, как цельным. Т.е. функции типа
Func(byte[] buffer, int offset, int length)можно просто превратить вFunc(Span<byte> buffer).Ну и главное, что Span - это не только управляемый массив, за ним может быть и неуправляемая память. Соответственно тебе достаточно будет написать одну функцию с реализацией для Span, вместо отдельных реализаций для
byte[]иbyte*. Хотя реализация в таком случае обычно сводятся к unsafe с fixed массива, но со Span можно писать safe реализацию, что тоже плюсом.Ну т.е. останется как раз та самая "примитивная фигня", с которой и нейронка справится? Об этом и речь.
В таком случае нужно не нейронкой восхищаться, а собой, раз сумел создать такую крутую архитектуру.
Ох ёёё... получается теперь в using EnterScope можно будет свободно await вызвать и компилятор слова не скажет. Прям замечательный выстрел в ногу будет для новичков (и не только).
А разве у вас в итоге получился не TaskSheduler?
Загуглите LimitedConcurrencyLevelTaskScheduler - это стандартная реализация от майков (в общем коде правда её нет). Ставите 1 поток и можно запускать в нем стандартные Task'и, которые так же будут друг за другом выполняться в пуле.
Что-то мне кажется, что не прокатит такая задумка. Проблема в том, что нельзя однозначно сказать, кто будет тем самым "предъявителем". К примеру, у вас есть контроллер, который запрашивает ISomeService и IControllerDependService, при этом ISomeService так же запрашивает IControllerDependService. Как вы будете резолвить нужный вашему контроллеру IControllerDependService, если первым его запросит ISomeService?
То, что вам нужно, это скорее возможность создавать дочерние провайдеры с заменой сервисов. И по идее можно реализовать собственный IControllerActivator, где как раз и делать подмену в зависимости от типа контроллера.
В том-то и прикол, что ошибки здесь не будет, будет warning. Такая проверка спокойно скомпилируется и запустится.
Это я придираюсь. Так-то понятно, что в такого рода задачах подразумевается класс, но всё же тип в данном случае влияет на решение.
Ну, в задаче не указан тип, так что если там структура, то null быть не может.
Ну если придираться к деталям, то мы ничего не знаем о типе в первом примере. Если это структура, то исправление будет совершенно иным.
Тут точно не скажешь. Эта виндовая служба любит отжирать под 80-100% от свободного места в оперативке под кэш (у меня прям сейчас 18 из 20Гб свободного съело). Правда, что оно туда кладёт - фиг его знает.
То это уже другая задача. В рамках этой можно и массивы сравнить.
Я не говорю, что вы неправильно делаете. Просто указываю на интересный момент.
Если сортировка строк подразумевает именно сортировку по коду каждого символа, то вроде как UTF-8 можно напрямую как массив байт сортировать - выйдет то же самое. Так можно избавится от лишних преобразований в string.
А про какую плотную интеграцию речь-то? Судя по примеру, просто добавили профиль публикации (PublishProfile, см. pubxml). Это по сути кастомный набор правил и команд для сборки и dotnet publish знать не знает, что этот DefaultContainer делает.
Я вот сразу обратил внимание на слишком высокие показатели удельной ёмкости по объёму — 900 Вт*ч/л. У меня в голове всегда висела цифра 400. Сейчас специально проверил и действительно, многие источники про литий ион говорят до 600, ну максимум 700 Вт*ч/л в лабораторных условиях. Проверил по источнику, который вы ниже дали, там около этой цифры есть указатель на источник, но ссылки в статье нет. Да и переход на первоисточник этого источника не дал результата.
Откуда взяли эту цифры (900) я честно говоря не могу понять. Если цифра реальная, то это же должно быть прорывом в мировом масштабе.