Страницы

Поиск по вопросам

пятница, 14 февраля 2020 г.

Выполнение синхронного кода в async методе

#c_sharp #async_await


Есть у меня promise метод чтения данных из моего потока:

public void ReadAsync(AsyncReadCallback callback, AsyncException exception
= null) {
    try {
        Thread thread = new Thread(new ThreadStart(() => {
            try {
                T request = ReadSync();
                callback.Invoke(ref request);
            } catch(Exception e) {
                if(exception == null) {
                    throw e;
                }
                exception.Invoke(e);
            }
        }));
        thread.Start();
    } catch (Exception e) {
        if(exception == null) {
            throw e;
        }
        exception.Invoke(e);
    }
}


Вызывать я его могу, соответственно так:

stream.ReadAsync((string result) => {
    Console.WriteLine("receive: "+result);
},(Exception e) => {
    Console.WriteLine("exception: "+e.Message);
});




Но, в погоне за сахаром, решил попробовать сделать аналогичное поведение через async,
что даст возможность выполнять всё без потоков, более того, заставлять делать await
в нужных мне местах:

public async Task ReadAsync() {
    return ReadSync();
}


Вызывать планирую, примерно так:

Task taskRead = stream.ReadAsync();
...
string data = await taskRead;
Console.WriteLine(data);


Однако, VS2017 говорит, что мой код будет выполняться только синхронно, и что там
нет await. Я не могу понять, возможно ли вообще то что я задумал?

Вот что говорит сама студия (скрин очень неудобный):

Всё что я хочу - выполнять синхронный метод так, как если бы он был асинхронен. (Возможно,
звучит глупо, но, не могу сформулировать по другому)
    


Ответы

Ответ 1



Ключевое слово async позволяет выполнять асинхронное ожидание других задач (делать await), но простое добавление этого слова ничего не дает вам в плане многопоточности. Перемещение выполнения в другой поток все еще остается именно вашей задачей. Выполнить задачу в фоновом потоке можно при помощи Task.Run: public Task ReadAsync() { return Task.Run(() => ReadSync()); } Однако, написание подобных оберток является дурной практикой: от асинхронного кода ожидается что он по крайней мере часть своей работы выполнит не занимая потока. Вероятно, правильным будет не делать отдельного метода ReadAsync - а вставить конструкцию Task.Run(() => ReadSync()) непосредственно в том месте где вам нужно прочитать данные: Task taskRead = Task.Run(() => stream.ReadSync()); ... string data = await taskRead; Console.WriteLine(data); А еще правильнее - переписать метод ReadSync так, чтобы он стал асинхронным.

Комментариев нет:

Отправить комментарий