Смысл в том, что в случае с REST мы не вызываем методы явно, а работаем с ресурсами. Естественно, на каком-то уровне какой-то код своим запросом мы выполним, но в случае REST нам неважно, что делает этот код, до тех пор, пока он выполняет нужные нам операции с ресурсами. Например, это может быть какой-то API сервис заметок - где мы будем создавать заметки, обновлять заметки, получать их и удалять, типа такого:
GET /notes
GET /notes/{id}
PUT /notes/{id} (или POST /notes)
PATCH /notes/{id}
DELETE /notes/{id}
Т е наш API не даёт нам возможность вызвать какую-то процедуру, давая нам вместо этого возможность работать с ресурсами. В случае с RPC можно было бы сделать какой-то такой API:
POST /getAllNotes
POST /getNoteById
POST /createNote
POST /updateNote
POST /deleteNote
Т е мы своими вызовами явно выполняем какие-то конкретные действия. Теперь мы можем сделать то, что обычно в REST не делается, например:
POST /backupNotes - такой метод мог бы сделать бэкап заметок, и отправить его куда-нибудь
POST /emailNote - типа отправить заметку на почту
POST /printNote - распечатать заметку
И так далее. Конечно, для работы с ресурсами (как заметки) - REST подходит намного лучше, даже выглядит как-то красивее и лаконичнее.
Я бы не стал приравнивать REST к RPC. REST вроде как больше ориентирован на работу с данными (CRUD операции по сути - создать / получить / обновить / удалить что-то), в то время как RPC - это именно удалённый вызов какой-то логики, любой. REST работает с ресурсами, в то время как RPC - с действиями, которые можно выполнять. Вроде как они даже в каком-то роде противоставляются друг другу - см. например вики - https://ru.wikipedia.org/wiki/REST):
Например, gRPC можно использовать для поднятия RPC канала локально, между приложением и сервисом, на одной машине. Чтобы REST для таких целей использовали - ни разу не видел.
Если есть какой-то generic переиспользуемый кэш, у которого может быть внутренняя ошибка чтения, наверное имеет смысл отдельно его покрыть юнит-тестами. Чтобы не было такого, что интеграционные тесты из-за него периодически падают. Одно другому в целом не мешает.
Тут есть нюансы. Во-первых, детерминированность чего? Во-вторых, ну замокаю я сервисы вью модели, проверю, что по нажатию кнопки что-то где-то вызвалось. Что на самом деле мне даёт такой тест? У нас в команде не идиоты работают, + qa, так что, вероятность того, что кто-то уберёт этот вызов по нажатию кнопки, крайне мала. Опять же, интеграционные тесты не пройдут после такого, так что qa даже билд не получит с такой проблемой. Зато, после рефакторинга, придётся ещё и этот бесполезный тест менять.
Интересный подход, но как по мне выглядит некрасиво. Мы у себя начали писать больше интеграционных тестов - они на самом деле покрывают бизнес логику так, как её видит бизнес, и дают хороший coverage. Unit тесты оставили только для каких-то часто используемых примитивов, типа своих observable collections или чего-то многопоточного, где на самом деле есть неочевидные граничные условия, которые необходимо покрывать. Вот после этого стало проще и интереснее.
Зачем нам надо обращать внимание на то, кто вызывает функцию Thread.Start
Ну как же, вы утверждаете, что асинхронный код создает потоки. Я же утверждаю, что это не так. Потоки в .NET запускаются чаще всего вызовом именно этого метода, поэтому обратить внимание стоило бы. Я бы на вашем месте обратил.
ну не равно, а что дальше то
Божественная аргументация :) Не думал, что это потребует дополнительных объяснений. Вот, например, есть у вас автомобиль, и вы его используете. У него есть двигатель. Верно ли будет сказать, что вы != двигатель, или вы несогласны? Вот, например, есть ДВС, а есть электродвигатель. ДВС загрязняет окружающую среду. Правда ли то, что если у вас есть автомобиль, вы загрязняете окружающую среду? А если там электродвигатель? А если он просто в гараже стоит?
Я честно говоря думал, что мысль крайне простая и доступная.
Пока не вижу, опять же, что, на практике, зависит от того, считаем мы, что асинхронный код может создавать потоки, или выносим эту функцию на какой-то другой уровень, чем отличается аренда потока от создания
Серьёзно? Вы не видите разницы между арендой потока и созданием? :)
получается, что вы просто хотите проигнорировать эту функциональность, типа: вот тут у меня асинхронный код, а все остальное меня не интересует
Это не совсем так работает. Это называется абстракция и декомпозиция - вот у нас есть контекст синхронизации (это абстракция), он будет отвечать за детали логики выполнения continuation'ов. И да, с точки зрения асинхронного кода то, как это будет происходить - я могу проигнорировать, так же, как это осознанно сделали разработчики .NET. Это значительно упрощает разработку.
Мне кажется, у нас с вами разное представление о том, что такое "асинхронный код" и что значит "создает потоки".
Код, который создает потоки - это код, который явно делает Thread.Start. Создание потоков, кстати, это относительно ресурсоёмкая операция, да и память отжирает понемногу.
Асинхронный код - это какой-то код внутри асинхронного метода с асинхронными вызовами (await), раскладываемый компилятором на стейт-машину.
Так вот, если вы явно не вызываете Thread.Start в своем асинхронном коде - он потоков не создает. Контекст может создавать новые потоки или переиспользовать в ходе выполнения асинхронного метода. Но контекст != асинхронный код. И то, что в каких-то случаях асинхронный код может использовать такой контекст, совершенно не обозначает, что асинхронный код создает потоки.
Грубо говоря, асинхронный метод делится на части и превращается в некоторую стейт машину. Можно сказать, что разделение проходит по await'ам. Т е до первого await'а выполнение происходит синхронно, затем стейт-машина эти кусочки (continuation'ы) по очереди шедулит в synchronization context.
В вашем случае, используется дефолтный контекст, который шедулит continuation'ы на потоки из тред-пула. Более того, вы не await'ите первый вызов, т е делаете fire and forget - глупо ожидать, что две параллельные задачи в таком контексте начнут выполняться на одном потоке.
То есть, эти потоки они уже есть в наличии, и их использование дефолтным контекстом вполне оправданно.
Что касается контекстов UI - ну, во-первых, название метода вообще ни о чем не говорит. Во-вторых, добавьте .ConfigureAwait(false) и получите немалый шанс того, что после этого await'а поток поменяется. Не потому, что кто-то создал новый поток. Просто для continuation'а может быть использован другой контекст - тот же дефолтный, на тред пуле.
У меня стойкое ощущение, что этот комментарий был ответом на что-то другое :)
Тем не менее. Совсем неясно, о каких табличках идет речь. enum в C# в целом используется точно так же, как и в других языках, где он есть. Значение по умолчанию для enum работает точно так же, как и для примитивных типов. Только если вы не путаете enum и Enum, который в чистом виде никто не использует.
Интересный подход, облегчаете задачу критикам. Однако, оригинал и перевод ничем визуально не отличаются, это усложняет чтение. Было бы круто оригинал выделить визуально как-то (например, курсивом) или убрать под спойлер. То же самое касается выделения слов, сильно пестрит - я уверен есть способ, который меньше бросается в глаза.
И все же интересно, как правильно - мультипроцессор или многопроцессор? У вас встречаются оба термина. А перейдя по ссылке в начале статьи увидел "Драйвер уровень" вместо "Уровень драйвера". Думаю в целом с переводами есть еще над чем поработать.
Да нет у меня никакого презрительного отношения, с чего вы это взяли. Каждому разработчику нужен редактор, чтобы редактировать какие-то отдельно взятые файлы (xml, json, или вот GH Actions) - в моем случае, это Notepad++, кто-то в моей команде использует VS Code, кто-то Sublime и т. д. - и это нормально и вопросов здесь никаких нет. Каждому инструменту своя область применения.
Но я пока что-то не вижу чтобы кто-то всерьёз делал крупные C# проекты на VS Code - с нормальным GUI, чтобы 100+ проектов было в солюшне и так далее. Почему-то все используют для этого VS или Rider, загадка правда?
Насколько я понимаю, ваш опыт в этом вопросе исходит из сравнения WebStorm и VS Code в плане разработки на js/ts. Вот честно, на js/ts +- можно хоть в блокноте писать, особенно на js. Так что вполне допускаю, что IDE для js не дает какого-то вау эффекта :)
Смысл в том, что в случае с REST мы не вызываем методы явно, а работаем с ресурсами. Естественно, на каком-то уровне какой-то код своим запросом мы выполним, но в случае REST нам неважно, что делает этот код, до тех пор, пока он выполняет нужные нам операции с ресурсами. Например, это может быть какой-то API сервис заметок - где мы будем создавать заметки, обновлять заметки, получать их и удалять, типа такого:
GET /notes
GET /notes/{id}
PUT /notes/{id} (или POST /notes)
PATCH /notes/{id}
DELETE /notes/{id}
Т е наш API не даёт нам возможность вызвать какую-то процедуру, давая нам вместо этого возможность работать с ресурсами. В случае с RPC можно было бы сделать какой-то такой API:
POST /getAllNotes
POST /getNoteById
POST /createNote
POST /updateNote
POST /deleteNote
Т е мы своими вызовами явно выполняем какие-то конкретные действия. Теперь мы можем сделать то, что обычно в REST не делается, например:
POST /backupNotes - такой метод мог бы сделать бэкап заметок, и отправить его куда-нибудь
POST /emailNote - типа отправить заметку на почту
POST /printNote - распечатать заметку
И так далее. Конечно, для работы с ресурсами (как заметки) - REST подходит намного лучше, даже выглядит как-то красивее и лаконичнее.
Я бы не стал приравнивать REST к RPC. REST вроде как больше ориентирован на работу с данными (CRUD операции по сути - создать / получить / обновить / удалить что-то), в то время как RPC - это именно удалённый вызов какой-то логики, любой. REST работает с ресурсами, в то время как RPC - с действиями, которые можно выполнять. Вроде как они даже в каком-то роде противоставляются друг другу - см. например вики - https://ru.wikipedia.org/wiki/REST):
Например, gRPC можно использовать для поднятия RPC канала локально, между приложением и сервисом, на одной машине. Чтобы REST для таких целей использовали - ни разу не видел.
Если есть какой-то generic переиспользуемый кэш, у которого может быть внутренняя ошибка чтения, наверное имеет смысл отдельно его покрыть юнит-тестами. Чтобы не было такого, что интеграционные тесты из-за него периодически падают. Одно другому в целом не мешает.
Тут есть нюансы. Во-первых, детерминированность чего? Во-вторых, ну замокаю я сервисы вью модели, проверю, что по нажатию кнопки что-то где-то вызвалось. Что на самом деле мне даёт такой тест? У нас в команде не идиоты работают, + qa, так что, вероятность того, что кто-то уберёт этот вызов по нажатию кнопки, крайне мала. Опять же, интеграционные тесты не пройдут после такого, так что qa даже билд не получит с такой проблемой. Зато, после рефакторинга, придётся ещё и этот бесполезный тест менять.
Интересный подход, но как по мне выглядит некрасиво. Мы у себя начали писать больше интеграционных тестов - они на самом деле покрывают бизнес логику так, как её видит бизнес, и дают хороший coverage. Unit тесты оставили только для каких-то часто используемых примитивов, типа своих observable collections или чего-то многопоточного, где на самом деле есть неочевидные граничные условия, которые необходимо покрывать. Вот после этого стало проще и интереснее.
Кампания героев была хорошей игрой для своего времени, но вот чтобы прямо топ-20 - крайне сомнительно
Не баг, а фича
Существует три проблемы программирования:
Именование переменных
Инвалидация кэшей
Групповые операции в плейлистах
Я вот тоже думал, что это шутка такая, а вы по сути что-то такое и утверждаете
Ну как же, вы утверждаете, что асинхронный код создает потоки. Я же утверждаю, что это не так. Потоки в .NET запускаются чаще всего вызовом именно этого метода, поэтому обратить внимание стоило бы. Я бы на вашем месте обратил.
Божественная аргументация :) Не думал, что это потребует дополнительных объяснений. Вот, например, есть у вас автомобиль, и вы его используете. У него есть двигатель. Верно ли будет сказать, что вы != двигатель, или вы несогласны? Вот, например, есть ДВС, а есть электродвигатель. ДВС загрязняет окружающую среду. Правда ли то, что если у вас есть автомобиль, вы загрязняете окружающую среду? А если там электродвигатель? А если он просто в гараже стоит?
Я честно говоря думал, что мысль крайне простая и доступная.
Серьёзно? Вы не видите разницы между арендой потока и созданием? :)
Это не совсем так работает. Это называется абстракция и декомпозиция - вот у нас есть контекст синхронизации (это абстракция), он будет отвечать за детали логики выполнения continuation'ов. И да, с точки зрения асинхронного кода то, как это будет происходить - я могу проигнорировать, так же, как это осознанно сделали разработчики .NET. Это значительно упрощает разработку.
Мне кажется, у нас с вами разное представление о том, что такое "асинхронный код" и что значит "создает потоки".
Код, который создает потоки - это код, который явно делает
Thread.Start
. Создание потоков, кстати, это относительно ресурсоёмкая операция, да и память отжирает понемногу.Асинхронный код - это какой-то код внутри асинхронного метода с асинхронными вызовами (await), раскладываемый компилятором на стейт-машину.
Так вот, если вы явно не вызываете
Thread.Start
в своем асинхронном коде - он потоков не создает. Контекст может создавать новые потоки или переиспользовать в ходе выполнения асинхронного метода. Но контекст != асинхронный код. И то, что в каких-то случаях асинхронный код может использовать такой контекст, совершенно не обозначает, что асинхронный код создает потоки.Не создает асинхронный код потоки :)
Грубо говоря, асинхронный метод делится на части и превращается в некоторую стейт машину. Можно сказать, что разделение проходит по await'ам. Т е до первого await'а выполнение происходит синхронно, затем стейт-машина эти кусочки (continuation'ы) по очереди шедулит в synchronization context.
В вашем случае, используется дефолтный контекст, который шедулит continuation'ы на потоки из тред-пула. Более того, вы не await'ите первый вызов, т е делаете fire and forget - глупо ожидать, что две параллельные задачи в таком контексте начнут выполняться на одном потоке.
То есть, эти потоки они уже есть в наличии, и их использование дефолтным контекстом вполне оправданно.
Что касается контекстов UI - ну, во-первых, название метода вообще ни о чем не говорит. Во-вторых, добавьте .ConfigureAwait(false) и получите немалый шанс того, что после этого await'а поток поменяется. Не потому, что кто-то создал новый поток. Просто для continuation'а может быть использован другой контекст - тот же дефолтный, на тред пуле.
fasm вроде как и в x86-64 умеет тоже
У меня стойкое ощущение, что этот комментарий был ответом на что-то другое :)
Тем не менее. Совсем неясно, о каких табличках идет речь. enum в C# в целом используется точно так же, как и в других языках, где он есть. Значение по умолчанию для enum работает точно так же, как и для примитивных типов. Только если вы не путаете enum и Enum, который в чистом виде никто не использует.
По-моему Visual Studio имеет community edition и в ней можно писать в том числе и на C.
А можно подробнее про Norton Commander?
https://github.com/dnSpyEx/dnSpy вот такое не пробовали использовать?
Интересный подход, облегчаете задачу критикам. Однако, оригинал и перевод ничем визуально не отличаются, это усложняет чтение. Было бы круто оригинал выделить визуально как-то (например, курсивом) или убрать под спойлер. То же самое касается выделения слов, сильно пестрит - я уверен есть способ, который меньше бросается в глаза.
И все же интересно, как правильно - мультипроцессор или многопроцессор? У вас встречаются оба термина. А перейдя по ссылке в начале статьи увидел "Драйвер уровень" вместо "Уровень драйвера". Думаю в целом с переводами есть еще над чем поработать.
Для заметок действительно подходит Google Keep, для простого планирования и списков задач TickTick бесплатной версии за глаза
Да нет у меня никакого презрительного отношения, с чего вы это взяли. Каждому разработчику нужен редактор, чтобы редактировать какие-то отдельно взятые файлы (xml, json, или вот GH Actions) - в моем случае, это Notepad++, кто-то в моей команде использует VS Code, кто-то Sublime и т. д. - и это нормально и вопросов здесь никаких нет. Каждому инструменту своя область применения.
Но я пока что-то не вижу чтобы кто-то всерьёз делал крупные C# проекты на VS Code - с нормальным GUI, чтобы 100+ проектов было в солюшне и так далее. Почему-то все используют для этого VS или Rider, загадка правда?
Насколько я понимаю, ваш опыт в этом вопросе исходит из сравнения WebStorm и VS Code в плане разработки на js/ts. Вот честно, на js/ts +- можно хоть в блокноте писать, особенно на js. Так что вполне допускаю, что IDE для js не дает какого-то вау эффекта :)