Dart: одновременные HTTP-запросы

Проблема: запросы Http.get в будущих функциях вызываются один за другим.

//this should open 5 simultaneous http connections
for (var i= 0; i < 5; i++) {
  getImage('[image soure]', i);
}

Я разделил код метода на несколько частей, чтобы лучше передать проблему.

import 'package:http/http.dart' as http;

void getImage(final String img, final int i) async {
  var blurHash = '';
  try {
    //PART: LOADING
    print('loading $img...');

    //PART: A
    var client = http.Client();

    var res = await client.get(img);

    print('$i: a');

    //PART: B
    var bbytes = res.bodyBytes;
    print('$i: b');

    //PART: C
    var l = bbytes.toList();
    print('$i: c');

    ...

    blurHash = '...';
  } catch (e) {
    print(e);
  }
}

Как должен выглядеть вывод консоли:

loading img.png
loading img.png
loading img.png
loading img.png
loading img.png
0: a
1: a
2: a
3: a
4: a
0: b
1: b
2: b
3: b
4: b
0: c
1: c
2: c
3: c
4: c

Как на самом деле выглядит вывод консоли:

loading img.png
loading img.png
loading img.png
loading img.png
loading img.png
0: a
0: b
0: c
1: a
1: b
1: c
2: a
2: b
2: c
3: a
3: b
3: c
4: a
4: b
4: c

Это означает, что часть загрузки выполняется одновременно, но похоже, что запросы http.get в Части A выполняются друг за другом.


person David Peters    schedule 01.06.2020    source источник
comment
getImage = generateBlurhash? Вы не await используете Future вызовы методов.   -  person Christopher Moore    schedule 01.06.2020
comment
Да, моя ошибка. Я обновил код.   -  person David Peters    schedule 01.06.2020
comment
Я не хочу ждать звонка в будущее. Я хочу, чтобы они работали одновременно.   -  person David Peters    schedule 01.06.2020
comment
Тогда почему фактический результат неожиданный? Фактический результат - 4 getImage Futures одновременно работающих, в то время как вы ожидаете, что они будут запущены по одному.   -  person Christopher Moore    schedule 01.06.2020
comment
Судя по ожидаемому результату, вы неправильно понимаете await. await не блокирует несколько экземпляров одного и того же Future. Это просто другой синтаксис для .then.   -  person Christopher Moore    schedule 01.06.2020
comment
Если я запустил for (var i= 0; i < 5; i++) { await getImage('[image soure]', i); }, несколько экземпляров getImage не будут выполняться одновременно. Или я неправильно понял ваш комментарий?   -  person David Peters    schedule 01.06.2020
comment
Я не предлагаю вам это сделать. Ваш код уже работает одновременно.   -  person Christopher Moore    schedule 01.06.2020


Ответы (1)


await someFuture (который, как объяснил Кристофер Мур в комментариях) является синтаксическим сахаром для return someFuture.then(...). Выполнение из вашей функции не может завершиться, если оно не вернет / не ожидает.

Вы можете явно разрешить своим функциям уступку, добавив несколько await null строк; это должно позволить вашим getImage вызовам чередоваться так, как вы хотите. Учтите, что это не ускорит работу; каждый изолятор Dart выполняет код Dart в одном потоке, поэтому, если вы не await выполняете асинхронную операцию, базовая реализация которой включает другой изолятор или поток, вы не сэкономите времени в целом. Добавление дополнительных awaits вместо этого приведет к большему переключению контекста и заставит все занять немного больше времени. (Это все еще может быть полезно, если вашему коду необходимо реагировать на другие события при выполнении дорогостоящих операций.)

person jamesdlin    schedule 01.06.2020
comment
Спасибо за ваш ответ. Я думаю, что http.get - проблемная часть. Как вы можете видеть в выходных данных, функции загружаются так, как я ожидал, до части a. Затем функция в основном ждала завершения предыдущего HTTP-запроса. Я тестировал for (var i= 0; i < 5; i++) { await getImage('[image soure]', i); }, но хочу, чтобы функция выполнялась одновременно, а не 5 раз подряд. - person David Peters; 01.06.2020
comment
@Velsem Как я объяснил, функция может дать выполнение только при использовании await (или возврате). После завершения вызова http.Client.get() getImage не использует никаких await, поэтому остальная часть вашей функции не может быть прервана. Опять же, вы не можете получить истинную одновременность, поскольку этот код в любом случае будет выполняться в одном потоке. Если вы хотите параллельное выполнение, вам нужно будет создать отдельные изоляты Dart. - person jamesdlin; 01.06.2020