{"id":623,"date":"2020-08-19T18:41:22","date_gmt":"2020-08-19T16:41:22","guid":{"rendered":"http:\/\/www.valeriofinazzo.it\/wordpress\/?p=623"},"modified":"2020-10-30T17:40:43","modified_gmt":"2020-10-30T16:40:43","slug":"tutorial-go-gestire-la-comunicazione-con-i-channel","status":"publish","type":"post","link":"http:\/\/www.valeriofinazzo.it\/wordpress\/2020\/08\/tutorial-go-gestire-la-comunicazione-con-i-channel\/","title":{"rendered":"TUTORIAL GO &#8211; GESTIRE LA COMUNICAZIONE CON I CHANNEL"},"content":{"rendered":"\n<p>Nell&#8217;articolo precedente abbiamo illustrato un primo meccanismo per notificare al ricevente la chiusura del channel, ovvero l&#8217;invio di una stringa dedicata che comunica la fine del flusso. Go mette a disposizione la funzione close con cui esplicitare che il canale \u00e8 stato chiuso, la chiusura non \u00e8 una operazione obbligatoria come nel caso dei file, ma permette di notificare al ricevente in modo esplicito la chiusura dello stream di dati.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">func workerCloser(channel chan string) {\n\tchannel &lt;- \"workerCloser\"\n\tclose(channel)\n}\nmain() {\n\tcanale4 := make(chan string)\n\tgo workerCloser(canale4)\n\tmsg3, ok := &lt;-canale4\n\tfmt.Println(msg3)\n\tmsg3, ok = &lt;-canale4\n\tif !ok {\n\t\tfmt.Println(\"Canale chiuso\")\n\t}\n}<\/pre>\n\n\n\n<p>Nell&#8217;esempio ho realizzato una funzione che scrive un messaggio e successivamente chiude il canale. Per capire se il canale \u00e8 stato chiuso o meno leggo il secondo parametro ok di tipo boolean che vale false qualora il canale sia stato chiuso esplicitamente.<\/p>\n\n\n\n<p>Insieme al close go mette a disposizione range, che avevamo visto usato per scorrere gli slices e che applicato ai channel permette di leggere tutti i valori nel channel fino alla chiusura.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">func contatore(channel chan int, max int) {\n\tfor i := 0; i &lt; max; i++ {\n\t\tchannel &lt;- i\n\t}\n\tclose(channel)\n}\nmain() {\n\tcanale5 := make(chan int, 10)\n\tgo contatore(canale5, 5)\n\tfor valore := range canale5 {\n\t\tfmt.Println(valore)\n\t}\n}<\/pre>\n\n\n\n<p>Nell&#8217;esempio ho creato una funzione contatore che riceve un parametro in ingresso e tramite ciclo for invia i parametri sul channel. Terminato il ciclo chiude il channel con il comando close. Nel main tramite il range leggo i valori dal channel e il ciclo si interrompe da solo. Notate che in questo caso il valore restituito dal range non l&#8217;indice ma il valore stesso.<\/p>\n\n\n\n<p>Go permette di gestire la lettura di pi\u00f9 channel concorrenti utilizzando la stessa goroutine. Per fare ci\u00f2 si avvale del comando select che consente la lettura dei valori da channel differenti. Come sintassi ricorda molto lo switch case.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">go func() {\n\t\tcanale6 &lt;- \"1\"\n\t\tcanale6 &lt;- \"2\"\n\t}()\n\n\tgo func() {\n\t\tcanale7 &lt;- \"3\"\n\t\ttime.Sleep(time.Second * 3)\n\t\tcanale7 &lt;- \"4\"\n\t}()\n\n\tfor i := 0; i &lt; 4; i++ {\n\t\tselect {\n\t\tcase mess1 := &lt;-canale6:\n\t\t\tfmt.Println(mess1)\n\t\tcase mess2 := &lt;-canale7:\n\t\t\tfmt.Println(mess2)\n\t\tdefault:\n\t\t\tfmt.Println(\"Niente\")\n\t\t}\n\t}<\/pre>\n\n\n\n<p>Nell&#8217;esempio ho creato 2 funzioni anonime che scrivono i messaggi su 2 channel separati, tramite il comando select inserito all&#8217;interno nel ciclo for recupero tutti i valori inviati. Nel caso di messaggi concorrenti la select sceglie casualmente quale processare per primo. Con lo statement default possiamo implementare della logica da eseguire qualora non sia presente alcun dato nei channel gestiti dal select. Senza default la select rimarr\u00e0 in attesa di messaggi dal channel ad ogni iterazione.<\/p>\n\n\n\n<p>Il costrutto select consente anche di implementare in modo agevole un meccanismo di timeout tramite la funzione After del package time.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\tfor i := 0; i &lt; 2; i++ {\n\t\tselect {\n\t\tcase mess1 := &lt;-canale6:\n\t\t\tfmt.Println(mess1)\n\t\tcase &lt;-time.After(time.Second * 2):\n\t\t\tfmt.Println(\"timeout\")\n\t\t}\n\t}<\/pre>\n\n\n\n<p>La funzione After simula la ricezione di un messaggio nel channel, in tal modo implementiamo una attesa di 2 secondi sul channel canale, trascorso il quale viene gestita la condizione di timeout.<\/p>\n\n\n\n<p>Infine qualora si voglia gestire l&#8217;accesso concorrente a risorse di pi\u00f9 goroutines Go mette a disposizioni le funzioni Lock e Unlock del package sync. I 2 comandi ci assicurano che solo un thread per volta potr\u00e0 eseguire il codice compreso tra i 2 statement<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">func (cont *contatoreStruct) somma(val int) {\n\tvar mutex sync.Mutex\n\tmutex.Lock()\n\tcont.counter = cont.counter + val\n\tmutex.Unlock()\n}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Nell&#8217;articolo precedente abbiamo illustrato un primo meccanismo per notificare al ricevente la chiusura del channel, ovvero l&#8217;invio di una stringa dedicata che comunica la fine del flusso. Go mette a disposizione la funzione close con cui esplicitare che il canale \u00e8 stato chiuso, la chiusura non \u00e8 una operazione obbligatoria come nel caso dei file, &hellip; <a href=\"http:\/\/www.valeriofinazzo.it\/wordpress\/2020\/08\/tutorial-go-gestire-la-comunicazione-con-i-channel\/\" class=\"more-link\">Continua la lettura di <span class=\"screen-reader-text\">TUTORIAL GO &#8211; GESTIRE LA COMUNICAZIONE CON I CHANNEL<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[148],"tags":[128,105],"_links":{"self":[{"href":"http:\/\/www.valeriofinazzo.it\/wordpress\/wp-json\/wp\/v2\/posts\/623"}],"collection":[{"href":"http:\/\/www.valeriofinazzo.it\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.valeriofinazzo.it\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.valeriofinazzo.it\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.valeriofinazzo.it\/wordpress\/wp-json\/wp\/v2\/comments?post=623"}],"version-history":[{"count":2,"href":"http:\/\/www.valeriofinazzo.it\/wordpress\/wp-json\/wp\/v2\/posts\/623\/revisions"}],"predecessor-version":[{"id":625,"href":"http:\/\/www.valeriofinazzo.it\/wordpress\/wp-json\/wp\/v2\/posts\/623\/revisions\/625"}],"wp:attachment":[{"href":"http:\/\/www.valeriofinazzo.it\/wordpress\/wp-json\/wp\/v2\/media?parent=623"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.valeriofinazzo.it\/wordpress\/wp-json\/wp\/v2\/categories?post=623"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.valeriofinazzo.it\/wordpress\/wp-json\/wp\/v2\/tags?post=623"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}