GithubHelp home page GithubHelp logo

homework_go's Introduction

Async homework

в этом задании мы пишем аналог unix pipeline, что-то вроде:

cat common.go | grep func | sort | uniq -c | sort -n  

когда STDOUT одной программы передаeтся как STDIN в другую программу

но в нашем случае эти роли выполняют каналы, которые мы передаeм из одной функции в другую.

само задание по сути состоит из двух частей

  • написание функции RunPipeline которая обеспечивает нам конвейерную обработку функций-воркеров, которые что-то делают.
  • написание нескольких функций, которые считают нам информацию по письмам пользователей

если кратко, то мы хотим запустить следующую цепочку:

cat emails.txt | SelectUsers | SelectMessages | CheckSpam | CombineResults

то есть мы получаем на вход имейлы юзеров, селектим их из "базы" и получаем каждому юзеру user_id. затем селектим по каждому user_id список писем(msg_id) этого юзера. дальше проверяем эти письма на спам и выдаем итоговый результат: какие у письма со спамом, а какие нет.

а теперь подробнее про реализацию этой цепочки:

  • SelectUsers()
    • in - string внутри interface{}. это имейлы юзеров
    • out - отдает структурки User{}. это результат функции GetUser()
    • особенности:
      • GetUser() выполняется 1 секунду. его можно вызывать параллельно для нескольких юзеров. это экономит время
      • у некоторых юзеров есть alias'ы(псевдонимы). то есть на вид это два разных имейла, но на самом деле это один и тот же юзер в базе. например "[email protected]" - это алиас к "[email protected]". SelectUsers() должен отдавать в out только уникальных юзеров.
  • SelectMessages()
    • in - User{} внутри interface{} от SelectUsers()
    • out - отдает MsgID. это айдишники писем юзеров - результат функции GetMessages()
    • особенности:
      • GetMessages() выполняется 1 секунду. его тоже можно вызывать параллельно.
      • но GetMessages() позволяет использовать "батчи". то есть за раз в нее можно запихнуть не 1 юзера, а несколько. максимальное кол-во юзеров = 2. то есть если мы хотим селектнуть у 10ти юзеров письма, то это можно сделать за 5 вызовов GetMessages(). в тестах проверяется, что кол-во вызовов оптимальное
  • CheckSpam()
    • in - MsgID внутри interface{}. это айдишники писем
    • out - MsgData{}. это структура с парой полей: id и факт того является ли письмо спамом. это результат работы HasSpam()
    • особенности:
      • HasSpam() симулирует поход в сервис антиспама, чтоб проверить письмо на наличие спама. один запрос выполняется за 100мс. и у этого сервиса есть "антибрут" - его нельзя вызывать бесконтрольно в кучу потоков. если сделать к нему более 5 параллельных запросов, то он начнет возвращать ошибку и данные о наличии спама вы не получите.
  • CombineResults()
    • in - MsgData внутри interface{}
    • out - string. это строки вида "<has_spam> <msg_id>", например "true 17696166526272393238"
    • особенности:
      • CombineResults() ждет все результаты из in, а потом сортирует их по наличию спама и по msg_id. то есть пример вывода может быть такой:

          true 123
          true 5555
          true 5556
          false 140
          false 3000
          false 3005
        

В чем подвох:

  • из-за описанных выше особенностей у вас либо не будет асинхрона и функции последовательно будут выполняться слишком долго
  • либо вы можете наоборот безконтрольно все распаралелить и тогда будут ошибки тк нарветесь на антибрут
  • либо вы не соптимизируетe запросы "батчами" и будете лишний раз вызывать функции
  • на все расчеты у нас 3 сек.

Код писать в spammer.go. Запускать как go test -v -race

пример лога, для теста TestTotal:

2023/01/01 11:26:21 [GetUser() 1.000449332s] args:[email protected] res:{6935840902946149476 [email protected]}
2023/01/01 11:26:21 [GetUser() 1.000461251s] args:[email protected] res:{12499983457589032104 [email protected]}
2023/01/01 11:26:21 [GetUser() 1.000632207s] args:[email protected] res:{2436524555453976083 [email protected]}
2023/01/01 11:26:21 [GetUser() 1.000856246s] args:[email protected] res:{6411680653583780021 [email protected]}
2023/01/01 11:26:21 [GetUser() 1.000894362s] args:[email protected] res:{15459287427396367812 [email protected]}
2023/01/01 11:26:21 [GetUser() 1.000934361s] args:[email protected] res:{1193889969480132348 [email protected]}
2023/01/01 11:26:21 [GetUser() 1.000910476s] args:[email protected] res:{13707254613635009050 [email protected]}
2023/01/01 11:26:21 [GetUser() 1.000992091s] args:[email protected] res:{14529939612954000739 [email protected]}
2023/01/01 11:26:21 [GetUser() 1.001022818s] args:[email protected] res:{14126455436348693091 [email protected]}
2023/01/01 11:26:21 [GetUser() 1.001016139s] args:[email protected] res:{12499983457589032104 [email protected]}
2023/01/01 11:26:22 [GetMessages() 1.000166253s] args:[{ID:14126455436348693091 Email:[email protected]}] res:[6652443725402098015 221945221381252775 9656111811170476016 221962074543525747] err:<nil>
2023/01/01 11:26:22 [GetMessages() 1.00059829s] args:[{ID:2436524555453976083 Email:[email protected]} {ID:6411680653583780021 Email:[email protected]}] res:[12728377754914798838 14498495926778052146 12975933273041759035 12386730660396758454 9323185346293974544 8065084208075053255 10523043777071802347 12792092352287413255 12556782602004681106 12026159364158506481] err:<nil>
2023/01/01 11:26:22 [GetMessages() 1.000343439s] args:[{ID:15459287427396367812 Email:[email protected]} {ID:1193889969480132348 Email:[email protected]}] res:[7594744397141820297 1877225754447839300] err:<nil>
2023/01/01 11:26:22 [GetMessages() 1.000365591s] args:[{ID:13707254613635009050 Email:[email protected]} {ID:14529939612954000739 Email:[email protected]}] res:[2803967521226628027 13245035231559086127 10493933060383355848 378045830174189628 10462184946173556768 10167774218733491071 11204847394727393252 10463884548348336960 15784986543485231004 16476037061321929257 17259218828069106373 4652873815360231330 357347175551886490 11512743696420569029 1595319133252549342 17696166526272393238] err:<nil>
2023/01/01 11:26:22 [GetMessages() 1.000755755s] args:[{ID:6935840902946149476 Email:[email protected]} {ID:12499983457589032104 Email:[email protected]}] res:[5108368734614700369 16728486308265447483 7829088386935944034 26236336874602209 15161554273155698590 14107154567229229487 15728889559763622673 15262116397886015961 59892029605752939 17087986564527251681] err:<nil>
2023/01/01 11:26:22 [HasSpam() 100.728826ms] args:14498495926778052146 res:false err:<nil>
2023/01/01 11:26:22 [HasSpam() 100.808515ms] args:12386730660396758454 res:true err:<nil>
2023/01/01 11:26:22 [HasSpam() 100.727841ms] args:12728377754914798838 res:true err:<nil>
2023/01/01 11:26:22 [HasSpam() 100.864612ms] args:12975933273041759035 res:false err:<nil>
2023/01/01 11:26:22 [HasSpam() 100.793487ms] args:6652443725402098015 res:false err:<nil>
2023/01/01 11:26:22 [HasSpam() 100.478291ms] args:221945221381252775 res:true err:<nil>
2023/01/01 11:26:22 [HasSpam() 100.613594ms] args:2803967521226628027 res:false err:<nil>
2023/01/01 11:26:22 [HasSpam() 100.809267ms] args:9323185346293974544 res:true err:<nil>
2023/01/01 11:26:22 [HasSpam() 100.646974ms] args:5108368734614700369 res:true err:<nil>
2023/01/01 11:26:22 [HasSpam() 101.083156ms] args:7594744397141820297 res:false err:<nil>
2023/01/01 11:26:22 [HasSpam() 100.900365ms] args:9656111811170476016 res:false err:<nil>
2023/01/01 11:26:22 [HasSpam() 100.846218ms] args:16728486308265447483 res:true err:<nil>
2023/01/01 11:26:22 [HasSpam() 101.563802ms] args:8065084208075053255 res:true err:<nil>
2023/01/01 11:26:22 [HasSpam() 101.528313ms] args:13245035231559086127 res:true err:<nil>
2023/01/01 11:26:22 [HasSpam() 101.388859ms] args:1877225754447839300 res:true err:<nil>
2023/01/01 11:26:23 [HasSpam() 100.415444ms] args:7829088386935944034 res:true err:<nil>
2023/01/01 11:26:23 [HasSpam() 100.775029ms] args:10493933060383355848 res:false err:<nil>
2023/01/01 11:26:23 [HasSpam() 100.571509ms] args:12792092352287413255 res:false err:<nil>
2023/01/01 11:26:23 [HasSpam() 100.631663ms] args:221962074543525747 res:false err:<nil>
2023/01/01 11:26:23 [HasSpam() 100.960382ms] args:10523043777071802347 res:false err:<nil>
2023/01/01 11:26:23 [HasSpam() 101.102036ms] args:10462184946173556768 res:false err:<nil>
2023/01/01 11:26:23 [HasSpam() 101.165203ms] args:15161554273155698590 res:false err:<nil>
2023/01/01 11:26:23 [HasSpam() 101.306838ms] args:12556782602004681106 res:true err:<nil>
2023/01/01 11:26:23 [HasSpam() 101.394269ms] args:26236336874602209 res:false err:<nil>
2023/01/01 11:26:23 [HasSpam() 101.545377ms] args:378045830174189628 res:false err:<nil>
2023/01/01 11:26:23 [HasSpam() 101.12091ms] args:11204847394727393252 res:true err:<nil>
2023/01/01 11:26:23 [HasSpam() 101.022293ms] args:15728889559763622673 res:false err:<nil>
2023/01/01 11:26:23 [HasSpam() 101.511417ms] args:12026159364158506481 res:true err:<nil>
2023/01/01 11:26:23 [HasSpam() 101.34448ms] args:14107154567229229487 res:true err:<nil>
2023/01/01 11:26:23 [HasSpam() 101.479134ms] args:10167774218733491071 res:false err:<nil>
2023/01/01 11:26:23 [HasSpam() 100.458353ms] args:16476037061321929257 res:true err:<nil>
2023/01/01 11:26:23 [HasSpam() 100.550921ms] args:59892029605752939 res:false err:<nil>
2023/01/01 11:26:23 [HasSpam() 100.674563ms] args:15262116397886015961 res:false err:<nil>
2023/01/01 11:26:23 [HasSpam() 100.737998ms] args:10463884548348336960 res:true err:<nil>
2023/01/01 11:26:23 [HasSpam() 100.700208ms] args:15784986543485231004 res:false err:<nil>
2023/01/01 11:26:23 [HasSpam() 101.22859ms] args:11512743696420569029 res:false err:<nil>
2023/01/01 11:26:23 [HasSpam() 101.34849ms] args:17087986564527251681 res:true err:<nil>
2023/01/01 11:26:23 [HasSpam() 101.455444ms] args:4652873815360231330 res:true err:<nil>
2023/01/01 11:26:23 [HasSpam() 101.603069ms] args:17259218828069106373 res:true err:<nil>
2023/01/01 11:26:23 [HasSpam() 101.523291ms] args:357347175551886490 res:true err:<nil>
2023/01/01 11:26:23 [HasSpam() 100.361413ms] args:1595319133252549342 res:true err:<nil>
2023/01/01 11:26:23 [HasSpam() 100.437573ms] args:17696166526272393238 res:true err:<nil>

Подсказки:

  • помните что порядок выполнения горутин заранее не предопредлен
  • задание построено так чтобы хорошо разобраться со всем материалом лекции, т.е. вдумчиво посмотреть примеры и применить их на практике. искать по гуглу или стек оферфлоу ничего не надо
  • вам не надо накапливать данные - сразу передаeм их дальше ( например awk из кода выше - на это есть отдельный тест. Разве что функция сама не решает накопить - у нас это CombineResults или sort из кода выше)
  • подумайте, как будет организовано завершение функции если данные конечны. Что для этого надо сделать?
  • если вам встретился рейс ( опция -race ) - исследуйте его вывод - когда читаем, когда пишем, из каких строк кода. там как правило содержится достаточно информации для нахождения источника проблемы.
  • прежде чем приступать к распараллеливанию функций, чтобы уложиться в отведeнный таймаут - сначала напишите линейный код, который будет выдавать правильный результат, лучше даже начать с меньшего количества значений чтобы совпадало с тем что в задании
  • ответ на вопрос "когда закрывается цикл по каналу" помогает в реализации RunPipeline
  • Хорошо помогает нарисовать схему рассчетов
  • естественно нельзя самим вычислять данные в обход предоставляемых функций - их вызов будет проверяться.
  • select в этом задании не нужен
  • time.Sleep использовать нельзя

Эталонное решение занимает 130 строк

homework_go's People

Contributors

gokert avatar

Watchers

Anton Sulaev avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.