3

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

public void ReadAsync<T>(AsyncReadCallback<T> callback, AsyncException exception = null) {
    try {
        Thread thread = new Thread(new ThreadStart(() => {
            try {
                T request = ReadSync<T>();
                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<T> ReadAsync<T>() {
    return ReadSync<T>();
}

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

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

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

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

andreycha
  • 25,167
  • 4
  • 46
  • 82
test123
  • 1,084
  • Ключевое слово async используется в тех методах, внутри которых есть await. В вашем методе ReadAsync await'ов нет – tym32167 Jan 19 '18 at 11:58
  • @tym32167, Поясните, то есть, эту задачу можно решать исключительно потоками? – test123 Jan 19 '18 at 11:59
  • 2
    Вам нужно понять, что асинхронный код != многопоточный код, и все сразу станет яснее :) – tym32167 Jan 19 '18 at 12:33
  • @tym32167, Вы хотите сказать, что в асинхронности не важен только порядок? Я представлю async, как нечто отдалённо напоминающее короутину. Возможно, поэтому заблуждаюсь. – test123 Jan 19 '18 at 12:49
  • 1
    Я хочу сказать, что возможно написать асинхронный код, который не задействует многопоточность. – tym32167 Jan 19 '18 at 13:36
  • 1
    Привяжу: https://ru.stackoverflow.com/a/491783/106 и https://ru.stackoverflow.com/a/498418/106 – andreycha Jan 19 '18 at 15:56
  • @andreycha, Огромное Спасибо! Целая куча полезной информации! – test123 Jan 22 '18 at 06:53
  • @test123 не за что! – andreycha Jan 22 '18 at 08:37

1 Answers1

5

Ключевое слово async позволяет выполнять асинхронное ожидание других задач (делать await), но простое добавление этого слова ничего не дает вам в плане многопоточности. Перемещение выполнения в другой поток все еще остается именно вашей задачей.

Выполнить задачу в фоновом потоке можно при помощи Task.Run:

public Task<T> ReadAsync<T>() {
    return Task.Run(() => ReadSync<T>());
}

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

Вероятно, правильным будет не делать отдельного метода ReadAsync - а вставить конструкцию Task.Run(() => ReadSync<T>()) непосредственно в том месте где вам нужно прочитать данные:

Task<string> taskRead = Task.Run(() => stream.ReadSync<T>());
...
string data = await taskRead;
Console.WriteLine(data);

А еще правильнее - переписать метод ReadSync так, чтобы он стал асинхронным.

Pavel Mayorov
  • 58,537
  • Спасибо! То что нужно. Не с проста я сомневался в том что всё настолько просто... Значит, никакой магии за async не стоит :( – test123 Jan 19 '18 at 12:07
  • 3
    @test123 еще как стоит. Но связана она исключительно со словом await. – Pavel Mayorov Jan 19 '18 at 12:08