Как понять appengine ndb.tasklet?
Из документации:
Тасклет NDB - это фрагмент кода, который может выполняться одновременно с другим кодом. Если вы пишете тасклет, ваше приложение может использовать его так же, как оно использует асинхронную функцию NDB: оно вызывает тасклет, который возвращает Future; позже вызов метода get_result() в Future возвращает результат.
Объяснение и примеры в документе действительно нравятся мне. Я могу использовать это, но мне трудно понять это правильно.
Например:
- Могу ли я поместить какой-либо код внутри функции и украсить его как ndb.tasklet? Затем использовал его как асинхронную функцию позже. Или это должен быть appengine RPC?
- Этот вид декоратора также работает на моем ПК?
- Это так же, как тасклет для Pypy
1 ответ
Если вы посмотрите на реализацию Future, она очень сравнима с тем, что есть у генератора в python. На самом деле, он использует тот же yield
ключевое слово для достижения того, что он говорит, что делает. Прочитайте вступительные комментарии к tasklets.py для некоторых разъяснений.
Когда вы используете декоратор @tasklet, он создает Future и ожидает значения в обернутой функции. Если значение является генератором, оно добавляет Future к циклу событий. Когда ты yield
в будущем цикл обработки событий проходит через ВСЕ фьючерсы в очереди, пока желаемое будущее не будет готово. Параллелизм здесь заключается в том, что каждое Future будет выполнять свой код до тех пор, пока не будет возвращено raise ndb.Return(...)
или функция завершается), генерируется исключение, или yield
используется снова. Я думаю, технически, вы можете использовать yield
в коде просто для того, чтобы прекратить выполнение этой функции в пользу продолжения цикла событий, запускающего другие Futures, но я бы предположил, что это не сильно поможет, если вы действительно не разберетесь в умном сценарии использования.
Чтобы ответить на ваши вопросы:
Технически да, но он не будет работать асинхронно. Когда вы декорируете непродуктивную функцию с помощью @tasklet, ее значение Future вычисляется и устанавливается при вызове этой функции. То есть он запускает всю функцию, когда вы ее вызываете. Если вы хотите добиться асинхронной работы, вы должны
yield
на то, что делает асинхронную работу. Обычно в GAE он работает вплоть до вызова RPC.Если под работой на вашем компьютере вы подразумеваете, что dev appserver реализует тасклеты / фьючерсы, как GAE, то да, хотя это более точно с devappserver2 (теперь по умолчанию в более новом SDK). На самом деле я не уверен на 100%, будут ли локальные вызовы RPC выполняться параллельно при использовании Futures, но есть цикл обработки событий, проходящий через Futures, будь то локальный или производственный. Если вы хотите использовать Future в другом, не GAE-коде, то я думаю, что вам лучше использовать встроенное будущее Python 3.2 (или найти бэкпорт здесь)
Вид, это не совсем простое сравнение. Посмотрите документацию здесь. Идея примерно такая же (планировщик можно сравнить с циклом событий), но реализация низкого уровня сильно отличается.