Skip to content

Instantly share code, notes, and snippets.

@devlights
Last active March 3, 2022 08:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save devlights/34abe278d594b12b75ccb5405fc632ff to your computer and use it in GitHub Desktop.
Save devlights/34abe278d594b12b75ccb5405fc632ff to your computer and use it in GitHub Desktop.
自分用 手慣らしの型 (go, csharp)
//
// 自分用の手慣らしの型
// 1.HttpClientでリクエストを出す(リクエストもそれぞれを非同期実行)
// 2.(1)の結果から <title> タグの中身を抽出
// 3.(2)の結果を出力
//
// エラー処理は面倒なので割愛している
//
// httpリクエストを非同期実行しているので
// 結果は毎回異なる可能性がある。
//
// REFERENCES:
// - https://devlights.hatenablog.com/entry/2020/04/20/032712
// - https://devblogs.microsoft.com/dotnet/an-introduction-to-system-threading-channels/
// - https://deniskyashif.com/2019/12/08/csharp-channels-part-1/
// - https://deniskyashif.com/2019/12/11/csharp-channels-part-2/
// - https://deniskyashif.com/2020/01/07/csharp-channels-part-3/
// - https://ufcpp.net/study/csharp/async/asyncstream/#await-foreach
//
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Threading.Channels;
class Kata
{
static async Task Main()
{
var httpCh = Channel.CreateUnbounded<string>();
var dataCh = Channel.CreateUnbounded<string>();
var httpTask = Task.Run(async () =>
{
var urls = new string[]{
"https://github.com/devlights/try-golang",
"https://github.com/devlights/gomy",
"https://github.com/devlights/goxcel",
"https://devlights.hatenablog.com"
};
var outCh = httpCh.Writer;
var tasks = new List<Task>();
foreach (var url in urls)
{
var t = Task.Run(async () =>
{
using (var client = new HttpClient())
{
var resp = await client.GetAsync(url);
var body = await resp.Content.ReadAsStringAsync();
await outCh.WriteAsync(body);
}
});
tasks.Add(t);
}
await Task.WhenAll(tasks);
outCh.Complete();
});
var dataTask = Task.Run(async () =>
{
const string sTag = "<title>";
const string eTag = "</title>";
var inCh = httpCh.Reader;
var outCh = dataCh.Writer;
await foreach (var body in inCh.ReadAllAsync())
{
var sIdx = body.IndexOf(sTag);
var eIdx = body.IndexOf(eTag);
var begin = sIdx + sTag.Length;
var end = eIdx;
var data = body.Substring(begin, end - begin);
await outCh.WriteAsync(data);
}
outCh.Complete();
});
var inCh = dataCh.Reader;
await foreach (var data in inCh.ReadAllAsync())
{
Console.WriteLine(data);
}
await httpTask;
await dataTask;
}
}
//
// 自分用の手慣らしの型
// 1.http.Get()でリクエストを出す(リクエストもそれぞれを非同期実行)
// 2.(1)の結果から <title> タグの中身を抽出
// 3.(2)の結果を出力
//
// httpリクエストを非同期実行しているので
// 結果は毎回異なる可能性がある。
//
package main
import (
"bytes"
"errors"
"fmt"
"io"
"net/http"
"os"
"sync"
)
func main() {
var (
httpCh = make(chan []byte)
dataCh = make(chan []byte)
errsCh = make(chan error, 1)
)
defer close(errsCh)
var (
urls = []string{
"https://github.com/devlights/try-golang",
"https://github.com/devlights/gomy",
"https://github.com/devlights/goxcel",
"https://devlights.hatenablog.com",
}
)
go func() {
defer close(httpCh)
var (
wg sync.WaitGroup
)
wg.Add(len(urls))
for _, url := range urls {
url := url
go func() {
defer wg.Done()
resp, err := http.Get(url)
if err != nil {
errsCh <- err
return
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
errsCh <- err
return
}
httpCh <- body
}()
}
wg.Wait()
}()
var (
titleTagNotFound = errors.New("title tag does not found")
)
go func() {
defer close(dataCh)
var (
sTag = []byte("<title>")
eTag = []byte("</title>")
)
for body := range httpCh {
var (
start = bytes.Index(body, sTag)
end = bytes.Index(body, eTag)
)
if start == -1 || end == -1 {
errsCh <- titleTagNotFound
return
}
var (
data = body[start+len(sTag) : end]
)
dataCh <- data
}
}()
LOOP:
for {
select {
case err := <-errsCh:
fmt.Fprintln(os.Stderr, err)
case data, open := <-dataCh:
if !open {
break LOOP
}
fmt.Printf("[title] %s\n", data)
}
}
fmt.Println("DONE")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment