Pull to refresh
56
0

Пользователь

Send message
По-видимому, вы оказались правы в том, что await ничего не запускает, даже холодный таск. Такой код у меня вывел только Start. Хотя, может, я что-то и упустил. )

static async Task LoadAsync() => await new Task(() => System.Console.WriteLine("Load Async"));
		
static Task Load() => new Task(() => System.Console.WriteLine("Load"));

static async void Test()
{
	System.Console.WriteLine("Start");
	await LoadAsync();
	await Load();
	System.Console.WriteLine("Finish");
}

public static void Main()
{
	Test();
	var i = 0;
	while (true)
	{
		i++;
	}
}
Если учесть правило
По умолчанию принято считать что любой таск когда-нибудь выполнится если только обратное не написано в документации.

то для меня вдвойне очевидно, что загрузка выполнится асинхронно в случае работы с тасками, потому что никаких WaitAll я не делаю. А поскольку и в других местах используются подобные конструкции, например, с Close (где её убрать нельзя), то для общности мне хочется оставить её и с Load, путь даже это чуть менее оптимально с точки зрения компиляции.

Конечно, если вы видите более серьёзные потенциальные проблемы в виде блокировок, например, то поделитесь…
Ну, не все же так хорошо понимают работу тасков, как вы, например. Как-никак увидев async...await человек понимает, что с тасками идёт работа.

В случае же LoadAsync, можно подумать, что я вообще по старинке вручную создаю поток без всяких тасков.
Думаю, каждый разработчик сам для себя решит, хороши рассмотренные расширения для него или же нет.

Всего лишь делюсь результатами.
Знаете, почему вообще появились многие идеи из текущей статьи? Меня просто обескураживают некоторые детали «обычного паттерн-матчинга», а с помощью кастомных расширений я могу избежать их применения в своём коде, пусть даже ценой небольшого падения производительности (во многих случаях это для меня не критично).

Если бы мне в нём всё сразу понравилось, то никаких альтернатив точно бы не изобретал.
Просто дело вот в чём, когда я вижу в коде конструкцию (например, на гитхабе)
...ForEach(async d => await d.Load())

мне срузу становится ясно, что загрузка идёт асинхронная, а вот
...ForEach(d => d.Load())

ни о чём не говорит, нужно лезть в имплементацию или заранее именовать методы, как LoadAsync (при условии, что это мой код, а не чужой).

Из этих соображений читаемости для меня сейчас всё равно предпочтительным остаётся первый вариант…
Благодарю за ответы! Узнал для себя что-то новое.

Последнее уточнение, для случая
...ForEach(async d => await d.Load())
компилятор сгененирует ощутимо менее оптимальный код, чем для
...ForEach(d => d.Load()), поэтому второй вариант предпочтительнее? Или дело в другом?
Для моих задач это допустимые «в разы».

И для меня, в первую очередь, важна предсказуемость встроенных языковых средств, чтобы интуитивно заменив IModel на var где это, в привычном понимании, равноценная замена, не получить другое поведение программы.
А что в документации? Если её нет, а просто интерфейс с таском?
Как вы относитесь к потенциальной фиче (частному случаю Check паттерна, родственного With)?

/* true|false */
GetModel() is {} m // null check

/* true|false */
GetModel() is {Name is {} s, City is var c} m

Тогда вопрос, как мне быть уверенным, что таск у меня вообще начнёт выполняться, а не просто вернётся в вызывающий метод?
Никак вам не различить эти ситуации. То, когда начнется выполнение, зависит от того, что внутри AnyTask, а не снаружи.
Если правильно понимаю вас, то при наличии интерфейса, как у меня, и абстрагируясь от конкретной имплементации документа, мне нужно явно указывать await у Load, чтобы гарантированно выполнить таск, верно? Или чего-то ещё не понимаю?
То есть ReadToEndAsync тоже сам начинает выполнять таск, как у меня при StartNew, не дожидаясь явного await?
Хорошо, два случая
var tasks = docs.Select(d => d.AnyTask()).ToArray();
docs.ForEach(async d => await d.AnyTask());


В первом случае хочу просто собрать таски и выполнить их потом. Во втором хочу начать выполнять немедленно. Как мне различить эти ситуации? В первом случае таски начнут выполняться сейчас же?

Что ж, теперь я понял, о чём вы. Спасибо, что уделили немного времени на ревью.

Насколько понимаю, если вместо StartNew буду использовать ReadToEndAsync, то тогда await убрать не смогу, верно? Или интуиция опять подводит?
В моём случае с Load я не могу убрать await, поскольку метод возвращает таск, который мне нужно запустить. Если бы это был асинхронный воид метод, то тогда да, можно было бы написать так

async void Load() => await ...
...ForEach(d => d.Load());
Насколько я понимаю, вызов async () => await SomeAsync() запускает таск, а вот () => SomeAsync() просто его возвращает, не запуская.

Task task
...
() => task = SomeAsync()


И как вообще я могу убрать await в таком случае?
...ForEach(async d => await d.Close() && Documents.Remove(d))
И на что вы мне предлагаете его заменить? Особенно в случае с Close, где мне важен результат выполнения…

Тасками я пользуюсь по большей части интуитивно и стараюсь избегать дебрей с контекстами синхронизации.

Information

Rating
Does not participate
Registered
Activity