Винни имел в виду дурацкую моду снимать концерты на мобильный телефон (параллельно с официальной съемочной командой, которая обладает телефокаторами и сделает видео во много раз лучше). Так что лицо певца можно в записи на ютубе рассмотреть во всех подробностях, а на концерте лучше все таки отрываться под любимую музыку.
Ну почему, вон те же Apple — копируешь в буфер щипком тремя пальцами к себе, вставляешь щипком от себя; фото сделанное телефоном, может сразу же появится на ПК и т.д.
Другое дело что "компьютерные динозавры" этим не пользуются, им файлы подавай.
IMHO файл это просто абстракция — а людям то нужны картинки, музыка и видео, которые несут им впечатления, а вовсе не "файлы".
Конечно, многим людям нравятся и носители информации сами по себе — пластинки, диски и, в случае "гиков", — файлы. Но все таки контент важнее носителя (исключение — когда сам носитель уже является музейной ценностью).
Условный Apple выкинул файлы из интерфейса (под капотом они никуда не делись), и предъявляет людям контент, а не носитель, и это и делает интерфейс удобным и доступным даже трехлетним детям.
Конечно же, у конечного юзера становится меньше "контроля" над "своей" информацией, но, как много раз доказано историей, для массовой аудитории удобство приложения всегда побеждает "контролируемость". Это противоречие из разряда "хранить золото в огороде или деньги в банке?". Большинство хранит деньги в банке, а фото в гугл-диске. Да и "деньги" это тоже абстракция. По хорошему надо бы хранить соль, картошку и спички, а не бумажки с президентами.
Надежность "облачного" хранения тоже страдает, но с другой стороны, затем пользователи и платят инженерам, чтобы они занимались надежностью, безопасностью и т.п. Потому что, согласитесь, не могут все до единого граждане заниматся безопасностью своих файлов (а так же выращивать пшеницу, делать одежду и т.п.), большинству людей например физическая безопасность поважнее сохранности файлов будет, и то на 90% она отдана на откуп государству.
Удивление автора насчет "новое против качественного" объясняется так же — большинству нужны "впечатления" а новая информация обычно впечатляет больше, чем качественная, но читанная-перечитанная. Именно поэтому обычных пользователей и не пугает так сильно риск потери файлов. Всегда можно новых накачать, и да и получше старых. А если уж файлы были такими ценными, то обычно они в интернете валяются в великом множестве.
Мне конечно же приведут в пример личные ценности, вроде архива семейных фотографий. И я с этими исключениями согласен. Я сам храню свой фотоархив на файл-сервере с рейдом + внешний USB диск в компьютере в другой стране.
Но с другой стороны, я чувствую, что не так уж и важен этот фото-архив. Может быть разок или два на пенсии просмотрю его (если доживу), а на его хранение, сортирование и копирование уходят драгоценные часы и дни моей жизни. Уж не лучше ли делать, как современные домохозяйки — сфоткал чадо — отправил в семейный чат, тети-дяти поохали, поставили смайликов — все испытали эмоции — всем хорошо. Нафига потом эти фото хранить. Прийдут же новые ситуации, новые дети-внуки. Живая жизнь всегда подкинет контента так сказать. И всегда нового.
Так что если человеку важны воспоминания, он архив хранит, а многим не так уж и важны, тогда и облако сойдет.
Основная моя мысль вот какая — чем дольше живу, тем больше понимаю, что собирая "нужные и важные" файлы, я на самом деле похож на мою бабушку, которая собирала всю жизнь "нужные и важные" тряпки, крупы и нитки. Вот и я, сколько не смотрю на свои фото из Гималаев, и близко нет того чувства, что было в реальных горах, только жалкий отблеск.
Друзья-коллекционеры носителей информации (один все стену дисками заставил, которые уж и не слушает, другой все винты забил старыми играми — новые некуда ставить) — лишь укрепляют эту мысль.
Что живое восприятие жизни куда важнее воспоминаний. И лучше поглядеть внимательнее на красивый закат, чем тянуть руку за телефоном, чтобы сделав кадр "на будущее", отправить его в архив на диске.
А с третьей, когда необходимо обработать или удалить парочку сотен тысяч файлов в конкретной директории, то только find и спасает, ибо он применяет -delete (-exec) в цикле по мере нахождения файлов, а все остальные команды (типа rm dir/*, some_command dir/*, etc) вначале пытаются распаковать список аргументов, на чем благополучно зависают.
А я думаю, что депутаты и приближенные первыми себе закажут модемы. Ведь это "Модно, сильно, молодёжно!" да и чебурнет не грозит тогда.
А запеленговать модем проблематично ибо используется ФАР и в стороны "светить" будет очень слабо.
До этих ваших GPS так и ориентировались, и самолеты и автопилоты ракет, начиная с Фау1, и даже статья на Хабре была, где описывалась система навигации Авто из 80х с гироскопами.
Ошибка навигации в закрытой системе накапливается конечно, так что иногда необходимо корректировать, это уже решалось по разному.
TLDR:
Есть митохондрии, из-за них вы можете болеть. А можете и не болеть. Иногда можно болеть и внезапно вылечиться. А иногда внезапно заболеть.
Спрогнозировать ничего невозможно, но таблетки купите, на всякий случай.
Допустим у нас есть дерево идентификаторов комментариев
Я описал узел дерева, который сразу же в себе содержит ID комментария И дочерние узлы.
class IdNode:
id: int
children: list
Далее:
Необходимо построить новое дерево, аналогичное исходному, узлами которого вместо идентификаторов являются десериализованные структуры (т.е. сами комментарии, если я правильно понял)
class MsgNode:
message: str # вместо ID - комментарий
children: list
Тот факт, что вы для решения задачи построили другие структуры данных (дерево отдельно, сообщения отдельно), не делает это решение неправильным.
P.S. хотя меня было цапарающее чувство, что одно дерево с разной нагрузкой это лучше чем два разных, так что ваше решение пожалуй правильнее, но я фокусировался тогда на асинхронности.
С опозданием на десять дней, но проверил — действительно asyncio.gather корректно собирает задачи из вложенного asyncio.gather и все просто работает асинхронно.
Вот полный код:
#!/usr/bin/env python
from dataclasses import dataclass, field
import aiohttp
import asyncio
@dataclass
class IdNode:
id: int
children: list = field(default_factory=list)
@dataclass
class MsgNode:
message: str
children: list
def __str__(self, indentation=""): # из комментария @Senpos ниже
message = f"{indentation}{self.message}"
children_messages = [child.__str__(indentation + '\t') for child in self.children]
return '\n'.join([message, *children_messages])
async def get_comment_by_id(x, session):
r = await session.get(f"https://jsonplaceholder.typicode.com/todos/{x}")
data = await r.json()
print('request', x, 'finished')
return data['title']
async def map_tree(node, session):
message, children = await asyncio.gather(
get_comment_by_id(node.id, session),
asyncio.gather(*[map_tree(child, session) for child in node.children])
)
return MsgNode(message, children)
async def main():
async with aiohttp.ClientSession() as session:
message_tree = await map_tree(
node=IdNode(1, [IdNode(2), IdNode(3, [IdNode(4), IdNode(5)])]),
session=session
)
print('\n', message_tree)
asyncio.run(main())
Вот так решение выглядит уже почти идеальным и сравнимо по читаемости с синхронной версией. Можно еще сделать ClientSession синглтоном, чтобы не прокидывать сессию через все функции, но это мелочи.
и в выводе сразу видно, что код не совсем асинхронный, вызовы к back-end асинхронны только для детей одного узла, но не всех узлов одновременно:
request 1 finished: delectus aut autem
request 2 finished: quis ut nam facilis et officia qui
request 3 finished: fugiat veniam minus
request 5 finished: laboriosam mollitia et enim quasi adipisci quia provident illum
request 4 finished: et porro tempora
(последние два вызова могут поменятся местами по времени, но 1..3 — никогда и это будет видно более ясно, если сделать дерево побольше)
Попытался решить задачу на питоне и наконец-то вроде даже понял, как работает asyncio.
Исходные структуры данных:
from dataclasses import dataclass
@dataclass
class IdNode:
"""tree for IDs"""
id: int
children: list
@dataclass
class MsgNode:
"""tree for messages"""
message: str
children: list
# initial tree with IDs
tree = IdNode(1, [
IdNode(2, []),
IdNode(3, [
IdNode(4, []),
IdNode(5, [])
])
])
print(tree)
Удаленная база сообщений (обращаюсь к ней через typicode, как и автор статьи) :
{
"messages": [
{
"id": 1,
"message": "1:Оригинальный комментарий"
},
{
"id": 2,
"message": "2:Ответ на комментарий 1"
},
{
"id": 3,
"message": "3:Ответ на комментарий 2"
},
{
"id": 4,
"message": "4:Ответ на ответ 1"
},
{
"id": 5,
"message": "5:Ответ на ответ 2"
}
],
"profile": {
"name": "typicode"
}
}
Синхронное решение задачи:
#!/usr/bin/env python
import requests
from data_structures import IdNode, MsgNode, tree
api_url = "https://my-json-server.typicode.com/AcckiyGerman/demo/messages/"
def get_comment_by_id(x):
url = api_url + str(x)
r = requests.get(url).json()
return r["message"]
def map_tree(node):
return MsgNode(
message=get_comment_by_id(node.id),
children=[map_tree(child) for child in node.children]
)
message_tree = map_tree(tree)
print(message_tree)
Асинхронное решение задачи:
#!/usr/bin/env python
import aiohttp
import asyncio
from data_structures import IdNode, MsgNode, tree
api_url = "https://my-json-server.typicode.com/AcckiyGerman/demo/messages/"
messages = {}
tasks = []
async def get_comment_by_id(x, session):
global messages
url = api_url + str(x)
r = await session.get(url)
data = await r.json()
messages[x] = data['message']
print(f"request {x} finished")
def initiate_tasks(node, session):
""" starts a task for each message id in the tree, but not await for result """
global tasks
tasks.append(get_comment_by_id(node.id, session))
for child in node.children:
initiate_tasks(child, session)
def map_tree(node):
global messages
return MsgNode(
message=messages[node.id],
children=[map_tree(child) for child in node.children]
)
async def main():
async with aiohttp.ClientSession() as session:
initiate_tasks(node=tree, session=session)
await asyncio.gather(*tasks)
message_tree = map_tree(tree)
print(message_tree)
if __name__ == "__main__":
asyncio.run(main())
Результаты:
$ time ./sync_fetch.py
IdNode(id=1, children=[IdNode(id=2, children=[]), IdNode(id=3, children=[IdNode(id=4, children=[]), IdNode(id=5, children=[])])])
MsgNode(message='1:Оригинальный комментарий', children=[MsgNode(message='2:Ответ на комментарий 1', children=[]), MsgNode(message='3:Ответ на комментарий 2', children=[MsgNode(message='4:Ответ на ответ 1', children=[]), MsgNode(message='5:Ответ на ответ 2', children=[])])])
real 0m1,762s
user 0m0,181s
sys 0m0,012s
$ time ./async_fetch.py
IdNode(id=1, children=[IdNode(id=2, children=[]), IdNode(id=3, children=[IdNode(id=4, children=[]), IdNode(id=5, children=[])])])
request 2 finished
request 3 finished
request 1 finished
request 5 finished
request 4 finished
MsgNode(message='1:Оригинальный комментарий', children=[MsgNode(message='2:Ответ на комментарий 1', children=[]), MsgNode(message='3:Ответ на комментарий 2', children=[MsgNode(message='4:Ответ на ответ 1', children=[]), MsgNode(message='5:Ответ на ответ 2', children=[])])])
real 0m0,473s
user 0m0,137s
sys 0m0,020s
Выводы — асинхронный питон довольно сложен даже для такой простой задачи.
Я потратил около 3-х часов времени, чтобы написать правильное асинхронное решение, и мне не очень нравится результат. Рекурсивного обхода не получилось из-за необходимости собрать асинхронные обращения к удаленному серверу в одном месте, так что пришлось вводить еще две глобальные структуры messages и tasks
Синхронное решение заняло 10 минут. Правда я никогда в работе с асинхронным питоном не работал.
Может кто-либо подскажет, как можно короче написать.
Винни имел в виду дурацкую моду снимать концерты на мобильный телефон (параллельно с официальной съемочной командой, которая обладает телефокаторами и сделает видео во много раз лучше). Так что лицо певца можно в записи на ютубе рассмотреть во всех подробностях, а на концерте лучше все таки отрываться под любимую музыку.
Я тоже думаю, что лучше фото на стене, чем на диске. В связи с ограниченностью места на стене, приходится выбирать лучшее из лучшего для печати.
Я тоже как раз об этом думал — было бы неплохо сделать два интерфейса:
Да, это и есть самый здравый подход. Свобода выбрать и тот и этот способ.
Ну почему, вон те же Apple — копируешь в буфер щипком тремя пальцами к себе, вставляешь щипком от себя; фото сделанное телефоном, может сразу же появится на ПК и т.д.
Другое дело что "компьютерные динозавры" этим не пользуются, им файлы подавай.
О, я был уверен что такую программу ктото уже написал, просто поискать руки не доходили! Щас то я свой архив пропесочу! :)
P.S. в репозитории так много Issues вследствие популярности, или вам не хватает времени их закрывать?
IMHO файл это просто абстракция — а людям то нужны картинки, музыка и видео, которые несут им впечатления, а вовсе не "файлы".
Конечно, многим людям нравятся и носители информации сами по себе — пластинки, диски и, в случае "гиков", — файлы. Но все таки контент важнее носителя (исключение — когда сам носитель уже является музейной ценностью).
Условный Apple выкинул файлы из интерфейса (под капотом они никуда не делись), и предъявляет людям контент, а не носитель, и это и делает интерфейс удобным и доступным даже трехлетним детям.
Конечно же, у конечного юзера становится меньше "контроля" над "своей" информацией, но, как много раз доказано историей, для массовой аудитории удобство приложения всегда побеждает "контролируемость". Это противоречие из разряда "хранить золото в огороде или деньги в банке?". Большинство хранит деньги в банке, а фото в гугл-диске. Да и "деньги" это тоже абстракция. По хорошему надо бы хранить соль, картошку и спички, а не бумажки с президентами.
Надежность "облачного" хранения тоже страдает, но с другой стороны, затем пользователи и платят инженерам, чтобы они занимались надежностью, безопасностью и т.п. Потому что, согласитесь, не могут все до единого граждане заниматся безопасностью своих файлов (а так же выращивать пшеницу, делать одежду и т.п.), большинству людей например физическая безопасность поважнее сохранности файлов будет, и то на 90% она отдана на откуп государству.
Удивление автора насчет "новое против качественного" объясняется так же — большинству нужны "впечатления" а новая информация обычно впечатляет больше, чем качественная, но читанная-перечитанная. Именно поэтому обычных пользователей и не пугает так сильно риск потери файлов. Всегда можно новых накачать, и да и получше старых. А если уж файлы были такими ценными, то обычно они в интернете валяются в великом множестве.
Мне конечно же приведут в пример личные ценности, вроде архива семейных фотографий. И я с этими исключениями согласен. Я сам храню свой фотоархив на файл-сервере с рейдом + внешний USB диск в компьютере в другой стране.
Но с другой стороны, я чувствую, что не так уж и важен этот фото-архив. Может быть разок или два на пенсии просмотрю его (если доживу), а на его хранение, сортирование и копирование уходят драгоценные часы и дни моей жизни. Уж не лучше ли делать, как современные домохозяйки — сфоткал чадо — отправил в семейный чат, тети-дяти поохали, поставили смайликов — все испытали эмоции — всем хорошо. Нафига потом эти фото хранить. Прийдут же новые ситуации, новые дети-внуки. Живая жизнь всегда подкинет контента так сказать. И всегда нового.
Так что если человеку важны воспоминания, он архив хранит, а многим не так уж и важны, тогда и облако сойдет.
Основная моя мысль вот какая — чем дольше живу, тем больше понимаю, что собирая "нужные и важные" файлы, я на самом деле похож на мою бабушку, которая собирала всю жизнь "нужные и важные" тряпки, крупы и нитки. Вот и я, сколько не смотрю на свои фото из Гималаев, и близко нет того чувства, что было в реальных горах, только жалкий отблеск.
Друзья-коллекционеры носителей информации (один все стену дисками заставил, которые уж и не слушает, другой все винты забил старыми играми — новые некуда ставить) — лишь укрепляют эту мысль.
Что живое восприятие жизни куда важнее воспоминаний. И лучше поглядеть внимательнее на красивый закат, чем тянуть руку за телефоном, чтобы сделав кадр "на будущее", отправить его в архив на диске.
Это вы немецкой литературы не читали. Немцы как завернут предложение на пару сотен слов, пока до конца дочитаешь, уже забываешь о чем оно.
А с третьей, когда необходимо обработать или удалить парочку сотен тысяч файлов в конкретной директории, то только find и спасает, ибо он применяет -delete (-exec) в цикле по мере нахождения файлов, а все остальные команды (типа
rm dir/*
,some_command dir/*
, etc) вначале пытаются распаковать список аргументов, на чем благополучно зависают.А выход один — линукс. Жалко, что в корпоративных условиях этот выход часто невозможен.
А я думаю, что депутаты и приближенные первыми себе закажут модемы. Ведь это "Модно, сильно, молодёжно!" да и чебурнет не грозит тогда.
А запеленговать модем проблематично ибо используется ФАР и в стороны "светить" будет очень слабо.
До этих ваших GPS так и ориентировались, и самолеты и автопилоты ракет, начиная с Фау1, и даже статья на Хабре была, где описывалась система навигации Авто из 80х с гироскопами.
Ошибка навигации в закрытой системе накапливается конечно, так что иногда необходимо корректировать, это уже решалось по разному.
TLDR:
Есть митохондрии, из-за них вы можете болеть. А можете и не болеть. Иногда можно болеть и внезапно вылечиться. А иногда внезапно заболеть.
Спрогнозировать ничего невозможно, но таблетки купите, на всякий случай.
Лучший рассказ, что я читал на Хабре.
Я бы даже эту расу полностью в мир идей поселил, без физической оболочки.
Прямо интересно стало сьездить и посмотреть на это место.
Исходная задача:
Я описал узел дерева, который сразу же в себе содержит ID комментария И дочерние узлы.
Далее:
Тот факт, что вы для решения задачи построили другие структуры данных (дерево отдельно, сообщения отдельно), не делает это решение неправильным.
P.S. хотя меня было цапарающее чувство, что одно дерево с разной нагрузкой это лучше чем два разных, так что ваше решение пожалуй правильнее, но я фокусировался тогда на асинхронности.
С опозданием на десять дней, но проверил — действительно
asyncio.gather
корректно собирает задачи из вложенногоasyncio.gather
и все просто работает асинхронно.Вот полный код:
Вот так решение выглядит уже почти идеальным и сравнимо по читаемости с синхронной версией. Можно еще сделать
ClientSession
синглтоном, чтобы не прокидывать сессию через все функции, но это мелочи.Я добавил печать результатов в get_comment :
и в выводе сразу видно, что код не совсем асинхронный, вызовы к back-end асинхронны только для детей одного узла, но не всех узлов одновременно:
(последние два вызова могут поменятся местами по времени, но 1..3 — никогда и это будет видно более ясно, если сделать дерево побольше)
Попытался решить задачу на питоне и наконец-то вроде даже понял, как работает
asyncio
.Исходные структуры данных:
Удаленная база сообщений (обращаюсь к ней через typicode, как и автор статьи) :
Синхронное решение задачи:
Асинхронное решение задачи:
Результаты:
Выводы — асинхронный питон довольно сложен даже для такой простой задачи.
Я потратил около 3-х часов времени, чтобы написать правильное асинхронное решение, и мне не очень нравится результат. Рекурсивного обхода не получилось из-за необходимости собрать асинхронные обращения к удаленному серверу в одном месте, так что пришлось вводить еще две глобальные структуры
messages
иtasks
Синхронное решение заняло 10 минут. Правда я никогда в работе с асинхронным питоном не работал.
Может кто-либо подскажет, как можно короче написать.
код на гитхабе
Завязка и описание мира мне понравились.
Но не понравились частые отвлечённые диалоги не по теме, и конец истории уж очень скомканный.