Орден пылевых светильников [дубликат]

Ответ Фабрисио на месте; но я хотел дополнить его ответ чем-то менее техническим, который фокусируется на аналогии, чтобы помочь объяснить концепцию асинхронности .


Аналогия ...

Вчера работа, которую я делал, требовала некоторой информации от коллеги. Я позвонил ему; вот как прошел разговор:

Me: Привет, Боб, мне нужно знать, как мы foo 'd bar ' d на прошлой неделе , Джим хочет сообщить об этом, и вы единственный, кто знает подробности об этом.

blockquote>

Боб: Конечно, но мне понадобится около 30 минут?

blockquote>

Я: Это замечательно Боб. Дайте мне звонок, когда у вас есть информация!

blockquote>

На этом этапе я повесил трубку. Поскольку мне нужна была информация от Боба, чтобы закончить мой отчет, я оставил отчет и пошел за кофе вместо этого, затем я догнал какой-то адрес электронной почты. 40 минут спустя (Боб медленно), Боб позвонил и дал мне информацию, в которой я нуждался. На этом этапе я возобновил свою работу с моим отчетом, так как у меня была вся информация, в которой я нуждался.


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

Me: Привет, Боб, мне нужно знать, как мы foo на панели 'd на прошлой неделе.

blockquote>

Боб: Конечно, но мне понадобится около 30 минут?

blockquote>

Я: Это замечательно Боб. Я подожду.

blockquote>

И я сидел и ждал. И ждал. И ждал. В течение 40 минут. Не делать ничего, кроме ожидания. В конце концов, Боб дал мне информацию, мы повесили трубку, и я закончил свой отчет. Но я потерял 40 минут производительности.


Это асинхронное и синхронное поведение

Это именно то, что происходит во всех примерах нашего вопроса. Загрузка изображения, загрузка файла с диска и запрос страницы через AJAX - это медленные операции (в контексте современных вычислений).

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

var outerScopeVar;    
var img = document.createElement('img');

// Here we register the callback function.
img.onload = function() {
    // Code within this function will be executed once the image has loaded.
    outerScopeVar = this.width;
};

// But, while the image is loading, JavaScript continues executing, and
// processes the following lines of JavaScript.
img.src = 'lolcat.png';
alert(outerScopeVar);

В приведенном выше коде мы запрашиваем JavaScript для загрузки lolcat.png, который операция sloooow . Функция обратного вызова будет выполнена после выполнения этой медленной операции, но в то же время JavaScript будет продолжать обрабатывать следующие строки кода; т.е. alert(outerScopeVar).

Вот почему мы видим предупреждение, показывающее undefined; так как alert() обрабатывается немедленно, а не после загрузки изображения.

Чтобы исправить наш код, все, что нам нужно сделать, - переместить код alert(outerScopeVar) в функцию обратного вызова. Вследствие этого нам больше не нужна переменная outerScopeVar, объявленная как глобальная переменная.

var img = document.createElement('img');

img.onload = function() {
    var localScopeVar = this.width;
    alert(localScopeVar);
};

img.src = 'lolcat.png';

Вы всегда будете видеть, что обратный вызов указан как функция , потому что это единственный способ в JavaScript определить код, но не выполнить его до конца.

Поэтому во всех наших примерах function() { /* Do something */ } является обратным вызовом; чтобы исправить все примеры, все, что нам нужно сделать, - это переместить код, который нуждается в ответе операции там!

* Технически вы можете использовать eval(), но eval() для этой цели является злом


Как мне ждать моего вызывающего абонента?

В настоящее время у вас есть код, похожий на этот:

function getWidthOfImage(src) {
    var outerScopeVar;

    var img = document.createElement('img');
    img.onload = function() {
        outerScopeVar = this.width;
    };
    img.src = src;
    return outerScopeVar;
}

var width = getWidthOfImage('lolcat.png');
alert(width);

Однако теперь мы знаем, что return outerScopeVar происходит немедленно; перед тем как функция обратного вызова onload обновила переменную. Это приводит к getWidthOfImage() возврату undefined и undefined.

Чтобы исправить это, нам нужно разрешить функции, вызывающей getWidthOfImage(), зарегистрировать обратный вызов, а затем переместить предупреждение ширины, которая должна находиться внутри этого обратного вызова,

function getWidthOfImage(src, cb) {     
    var img = document.createElement('img');
    img.onload = function() {
        cb(this.width);
    };
    img.src = src;
}

getWidthOfImage('lolcat.png', function (width) {
    alert(width);
});

... как и прежде, обратите внимание, что нам удалось удалить глобальные переменные (в данном случае width).

12
задан ThiefMaster 4 September 2014 в 08:53
поделиться

3 ответа

Самый простой способ управления порядком выполнения светильников - просто запросить предыдущее крепление в более позднем приборе. Поэтому, чтобы убедиться, что b работает до a:

@pytest.fixture(autouse=True, scope="function")
def b():
    pass

@pytest.fixture(scope="function")
def a(b):
    pass
14
ответ дан Chronial 27 August 2018 в 23:39
поделиться

У меня была эта проблема с двумя function -скрытыми автозаменами. Я хотел, чтобы fixture b запускался до фиксации a, но каждый раз a работал первым. Я предположил, что это был алфавитный порядок, поэтому я переименовал a в c, и теперь b запускается первым. По-видимому, Pytest не документировал это. Это была просто счастливая догадка. : -)

Это для автономных светильников. Рассматривая более широкие области (например, module, session), прибор выполняется, когда pytest сталкивается с тестом, который ему нужен. Поэтому, если есть два теста, и первый тест использует приспособление с session с именем sb, а не имя с именем sa, тогда sb будет выполнено сначала. Когда следующий тест будет запущен, он начнет sa, предположив, что он требует sa.

5
ответ дан ebeezer 27 August 2018 в 23:39
поделиться

IIRC вы можете полагаться на более высокоуровневые светильники, которые должны быть выполнены в первую очередь. Поэтому, если вы создали привязку для аутсорсинга, привязанную к сеансу, для monkeypatch smtplib.SMTP.connect, вы можете создать прибор с привязкой к функциям, который отменяет этот monkeypatching для одного теста, после чего восстанавливает его. Я предполагаю, что самый простой способ сделать это - создать свой собственный механизм smtpserver, который зависит как от приспособления disallow_smtp, так и от smtpserver крепления от pytest-localserver, а затем обрабатывает все настройки и разрывы, необходимые для того, чтобы эти две работы вместе.

Это неопределенно, так как pytest-django обрабатывает доступ к базе данных через btw, вы можете попробовать и посмотреть на код там, но это далеко не простой пример и имеет много своих собственных странных вещей.

3
ответ дан flub 27 August 2018 в 23:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: