# Resposta da prova de concorrente Ideia do enunciado da prova, não lembro exatamente o que era pra fazer: Implementar duas funções `exec_load` e `exec`. A função `exec_load` recebe uma lista de requisições e cada requisiçao tem uma requisição "pai", apenas uma, menos a requisição 0, que não tem pai. A função exec implementa a chamada a uma função que fará a requisição, porém se a requisiçao demorar mais que 5 segundos ele tem q dar timeout e se a requisição der timeout ela tem que retornar -1, caso contrário deve retornar 0. Além disso, a função `exec_load` recebe um parametro que é o *max_workers*, sendo esse o número máximo de requisições que podem estar executando ao mesmo tempo. Por fim, a principal restrição do problema é: Uma requisição só pode ser executada depois que os seus antepaçados são executados. ## ìndice - [Tipo Request](#tipo-request) - [Definindo o tipo Node](#Definindo-tipo-novo) - [Executando de fato a requisicao](#Executando-de-fato-a-requisicao) - [Relacionando o node a execucao](#Relacionando-o-node-a-execucao) - [A função exec_load](#A-funcao-exec_load) - [Código completo](#Codigo-completo) ## Tipo request ```go= type request struct { req_id int antpassado_id int succs []int } ``` Tipo request que foi dado na questão para manipularmos ## Definindo tipo novo ```go= type node struct { req_id int succs []Node // Os filhos do nó atual } ``` Tipo nó que possui os atributos: - `req_id` *(int)*: Id da requisição que esse nó deve fazer; - `succs` *(Node list)*: Lista de filhos (do tipo *Node* também) que esse nó possui; ## Executando de fato a requisicao A função a seguir serve para fazer de fato a requisição, essa é uma função que foi exigida que nós implementassemos. ```go= func exec(r request) int { ticker := time.Ticker(5 * time.Second) reqChan := make(chan int, 1) go do_exec(r, reqchan) select { case <- ticker: return -1 case <- reqChan: return 0 } } ``` Na função acima temos: - **ticker**: Em Go o `time.ticker` retorna um canal que a cada 5 segundos, nesse caso, adiciona no canal um valor aleatorio padrao do tipo, 0 nesse caso, acho); - **do_exec**: Função abstraída que vai servir para fazer de fato a requisição, ela recebe o objeto requisição passado como parâmetro da função e o canal cujo o valor de retorno da requisição vai ser adicionado; - **reqChan**: Canal que vai servir para colocarmos o resultado da requisição. Agora vamos para o **select**. O select serve pra a gente dizer pra os canais que estao nas clausulas `case` assim: "Olhe vcs dois, quero o conteúdo que tem no canal de vcs, mas vou pegar o primeiro que chegar!", dessa forma, se a requisição demorar mais do que 5 segundos a função retorna -1, caso contrário retona 0. ## Relacionando o node a execucao ```go= func execReq(node Node, bufferReq chan int) { req := request(node.req_id) bufferReq <- req_id result := exec(req) <- bufferReq for soc in node.soccs { execReq(soc, bufferReq) } } ``` Na função acima temos: - **request()**: Função que não precisa implementar que recebe o id da requisição do nó e retorna a requisição de fato; - **bufferReq**: Canal que servirá para limitarmos a quantidade máxima de requisições que são executadas de forma paralela; As linhas 3-5 da função acima tem como objetivo evitar que um número de requisições que seja maior do que o tamanho do buffer sejam executadas ao mesmo tempo, dessa forma, antes de executar a função [exec](#Executando-de-fato-a-requisicao) é adicionado no buffer um número arbitrario e depois de executada a função é retirado um valor do buffer, dando lugar a outra gouroutine qu esteja bloqueada esperando uma vaga para executar sua requisição. Nas linahs 7 e 8 cada filho do nó atual roda a função `execReq`, sendo essa uma função recursiva que vai ser retornada quando o chegarmos nos nós folha. ## A funcao exec_load ```go= func exec_load(workload []request, max_workers int) { bufferRequest := make(chan int, max_workers) rootNode := createTree(workload) execReq(rootNode, bufferRequest) } ``` Na função acima temos: - **bufferRequest** *(chan int)*: Canal buffer que servirá para controlar a quantidade de requisições que podem ser feitas de forma paralela; - **createTree** *(func)*: Função arbitraria que não precisou ser implementada, mas que transforma a lista de requests em uma árvore e retorna o nó raiz. Essa função precisava ser implementada e é a que inicia todo o processo de chamadas das requisições, a partir do nó raiz. ## Codigo completo ```go= type node struct { req_id int succs []Node // Os filhos do nó atual } func exec(r request) int { ticker := time.Ticker(5 * time.Second) reqChan := make(chan int, 1) go do_exec(r, reqchan) select { case <- ticker: return -1 case <- reqChan: return 0 } } func execReq(node Node, bufferReq chan int) { req := request(node.req_id) bufferReq <- req_id result := exec(req) <- bufferReq for soc in node.soccs { execReq(soc, bufferReq) } } func exec_load(workload []request, max_workers int) { bufferRequest := make(chan int, max_workers) rootNode := createTree(workload) execReq(rootNode, bufferRequest) } ```