Разница между последовательным и параллельным - PullRequest
0 голосов
/ 04 июня 2018

Я выбираю некоторых людей из API и затем выполняю их параллельно, как будет выглядеть код, если я сделаю это в последовательном режиме?Даже не уверен, что если ниже параллельно, я с трудом выясняю разницу между ними.

Я полагаю, что серийный номер один за другим, и параллельный (promise.all) ждетдля всех обещаний, которые должны быть решены, прежде чем он поместит значение в finalResult?

Правильно ли это понято?

Ниже приведен фрагмент моего кода.

Заранее спасибо.

const fetch = require('node-fetch')
    const URL = "https://swapi.co/api/people/";

    async function fetchPerson(url){

        const result = await fetch(url);
        const data = await result.json().then((data)=>data);
        return data ;
    }

    async function printNames() {
      const person1 = await fetchPerson(URL+1);
      const person2 = await fetchPerson(URL+2);
      let finalResult =await Promise.all([person1.name, person2.name]);
      console.log(finalResult);
    }

    printNames().catch((e)=>{

      console.log('There was an error :', e)

      });

Ответы [ 2 ]

0 голосов
/ 04 июня 2018

Позвольте мне перевести этот код в несколько разных версий.Во-первых, оригинальная версия, но с удаленной дополнительной работой:

const fetch = require('node-fetch')
const URL = "https://swapi.co/api/people/";

async function fetchPerson(url){
    const result = await fetch(url);

    return await result.json();
}

async function printNames() {
  const person1 = await fetchPerson(URL+1);
  const person2 = await fetchPerson(URL+2);

  console.log([person1.name, person2.name]);
}


try {
  await printNames();
} catch(error) {
  console.error(error);
}

Приведенный выше код эквивалентен исходному коду, который вы опубликовали.Теперь, чтобы лучше понять, что здесь происходит, давайте переведем это на точно такой же код. Pre- async / await.

const fetch = require('node-fetch')
const URL = "https://swapi.co/api/people/";

function fetchPerson(url){
    return fetch(url).then((result) => {
      return result.json();
    });
}

function printNames() {
  let results = [];

  return fetchPerson(URL+1).then((person1) => {
    results.push(person1.name);

    return fetchPerson(URL+2);
  }).then((person2) => {
    results.push(person2.name);

    console.log(results);
  });
}


printNames().catch((error) => {
  console.error(error);
});

Код выше эквивалентен исходному коду, который вы разместилиЯ только что сделал дополнительную работу, которую сделает переводчик JS.Я чувствую, что это делает это немного более ясным.Следуя приведенному выше коду, мы сделаем следующее:

  1. Позвоните printNames()
  2. printNames(), запросите person1 и дождитесь ответа.
  3. printNames() запросит person2 и дождется ответа.
  4. printNames() напечатает результаты

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

const fetch = require('node-fetch')
const URL = "https://swapi.co/api/people/";

function fetchPerson(url){
    return fetch(url).then((result) => {
      return result.json();
    });
}

function printNames() {
  return Promise.all([fetchPerson(URL+1).then((person1) => person1.name), fetchPerson(URL+2).then((person2) => person2.name)]).then((results) => {
    console.log(results);
  });
}


printNames().catch((error) => {
  console.error(error);
});

Этот код НЕ эквивалентен опубликованному исходному коду.Вместо того, чтобы выполнять все последовательно, мы теперь выбираем разных пользователей параллельно.Теперь наш код выполняет следующие действия:

  1. Звоните printNames()
  2. printNames() Будет
    • Отправить запрос на person1
    • Отправитьзапрос person2
  3. printNames() будет ожидать ответа на оба запроса
  4. printNames() выведет результаты

Мораль этой истории в том, что async / await не является заменой Обещаниям во всех ситуациях, это синтаксический сахар, позволяющий упростить работу с Обещаниями.Если вы хотите / можете выполнять задачи параллельно, не используйте async / await.

Отказ от ответственности

printNames() (и все остальное)на самом деле ждать ничего.Он продолжит выполнение любого и всего кода, который идет после ввода-вывода, который не появляется в обратном вызове для ввода-вывода.await просто создает обратный вызов оставшегося кода, который вызывается после завершения ввода-вывода.Например, следующий фрагмент кода не будет делать то, что вы ожидаете.

const results = Promise.all([promise1, promise2]);

console.log(results);  // Gets executed immediately, so the Promise returned by Promise.all() is printed, not the results.

Serial vs. Parallel

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

Во-первых, я считаю разумным сказать, что JS не поддерживает параллельные операции в той же среде JS .В частности, в отличие от других языков, где я могу раскрутить поток для параллельного выполнения любой работы, JS может (кажется, выполнять) работу параллельно, только если кто-то выполняет работу (I / O).

ЭтоПри этом давайте начнем с простого описания того, как выглядит последовательный или параллельный .Представьте, если хотите, делать домашнее задание для 4 разных классов.Время, необходимое для выполнения домашней работы каждого класса, можно увидеть в таблице ниже.

Class | Time
1     | 5
2     | 10
3     | 15
4     | 2

Естественно, ваша работа будет выполняться последовательно и будет выглядеть примерно так:

You_Instance1: doClass1Homework() -> doClass2Homework() -> doClass3Homework() -> doClass4Homework()

ВыполнениеДомашнее задание серийно заняло бы 32 единицы времени.Однако не было бы замечательно, если бы вы могли разделить себя на 4 разных экземпляра себя?Если бы это было так, вы могли бы иметь экземпляр себя для каждого из ваших классов.Это может выглядеть примерно так:

You_Instance1: doClass1Homework()
You_Instance2: doClass2Homework()
You_Instance3: doClass3Homework()
You_Instance4: doClass4Homework()

Работая параллельно, вы можете закончить домашнюю работу за 15 единиц времени!Это меньше, чем половина времени.

«Но подождите, - говорите вы, - должен быть какой-то недостаток, чтобы разделить себя на несколько экземпляров, чтобы выполнить домашнее задание, или все будут делать это».

Вы правы.Есть некоторые накладные расходы на разделение себя на несколько экземпляров.Допустим, что расщепление требует глубокой медитации и опыта вне тела, что занимает 5 единиц времени.Теперь завершение домашней работы будет выглядеть примерно так:

You_Instance1: split() -> split() -> doClass1Homework()
You_Instance2:            split() -> doClass2Homework()
You_Instance3:                       doClass3Homework()
You_Instance4:                       doClass4Homework()

Теперь вместо 15 единиц времени на выполнение домашнего задания уходит 25 единиц времени.Это все же дешевле, чем делать всю домашнюю работу самостоятельно.

Резюме (пропустите здесь, если вы понимаете последовательное или параллельное выполнение)

Это может быть глупым примером, но это именно то, как выглядит последовательное или параллельное выполнение.Основным преимуществом параллельного выполнения является то, что вы можете выполнять несколько длительных задач одновременно.Поскольку несколько работников делают что-то одновременно, работа выполняется быстрее.

Однако есть и недостатки.Два из больших - это накладные расходы и сложность.Выполнение кода параллельно не является бесплатным, независимо от того, какую среду / язык вы используете.В JS параллельное выполнение может быть довольно дорогим, потому что это достигается путем отправки запроса на сервер.В зависимости от различных факторов, поездка в оба конца может занять от 10 до 100 миллисекунд.Это очень медленно для современных компьютеров.Вот почему параллельное выполнение обычно резервируется для долго выполняющихся процессов (выполнение домашней работы) или когда его просто невозможно избежать (загрузка данных с диска или сервера).

Другим основным недостатком является дополнительная сложность.Координация нескольких задач, происходящих параллельно, может быть трудной ( Обеденные философы , Проблема потребителя-производителя , Голодание , Условия гонки ).Но в JS сложность также заключается в понимании кода ( Callback Hell , понимании того, что когда выполняется).Как упомянуто выше, набор инструкций, встречающихся после асинхронного кода, не ожидает выполнения до тех пор, пока асинхронный код не завершится (если это не происходит в обратном вызове).

Как я могу заставить несколько экземпляров себя делатьмоя домашняя работа в JS?

Есть несколько способов сделать это.Один из способов сделать это - настроить 4 разных сервера.Давайте назовем их class1Server, class2Server, class3Server и class4Server.Теперь, чтобы эти серверы выполняли домашнюю работу параллельно, вы должны сделать что-то вроде этого:

Promise.all([
  startServer1(),
  startServer2(),
  startServer3(),
  startServer4()
]).then(() => {
  console.log("Homework done!");
}).catch(() => {
  console.error("One of me had trouble completing my homework :(");
});

Promise.all() возвращает Обещание, которое либо разрешается, когда все Обещания разрешены, либоотклоняет, когда один из них отклоняется.

0 голосов
/ 04 июня 2018

Обе функции fetchPerson и printNames работают последовательно, так как вы await получаете результаты.Использование Promise.all в вашем случае бессмысленно, поскольку оба человека уже были await ed (решены).

Для выборки двух человек параллельно:

const [p1, p2] = await Promise.all([fetchPerson(URL + '1'), fetchPerson(URL + '2')])

Имеются две асинхронные функции:

const foo = async () => {...}
const bar = async () => {...}

Это серийный номер:

const x = await foo()
const y = await bar()

Thisпараллельно:

const [x,y] = await Promise.all([foo(), bar()])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...