getConn()
想要进行数据传输首先就是要获取连接。

每一个 Request 都会提取出 协议 和目的地址形成 connectMethod ,然后生成一个 ConnMethodKey 用来表示与这台主机所有的连接,如果没有连接,那就新建一个连接。persistConn 相当于一个数据栈,每次取都会拿最后放上去的连接。
而 idelConnCh 每次有可用的连接都会第一时间拿给将要使用的 Request ,只有当获得连接的整个过程中都没有空闲的连接,才会使用 dialConn() 来新建连接。

如果这里面有连接那就简单多了,直接取用就可以了,特别的事persistConn 相当于一个数据栈,每次取都会拿最后放上去的连接。每次取用之后都会将连接从 map 中删除
if len(pconns) == 1 {pconn = pconns[0]delete(t.idleConn, key)// 只有一个连接,直接删除 map} else {pconn = pconns[len(pconns)-1]t.idleConn[key] = pconns[:len(pconns)-1]// 拿取最后的 conn}
DialConn()
在获取连接中,这个函数新建了 persistConn ,默认情况下上 Dial() 都是使用 net 包中普通的 Dial() 进行拨号,当然我们也可以自己给他指定要使用的 Dial() 和 DialTLS()

在进行拨号之后,还新建了两个 gorounite 分别作为读取和写入的入口。
persistconn.roundTrip()
获取连接之后,直接调用 persistconn.roundTrip() 获得 Response 
readLoop()

在创建 persistconn 的时候, readLoop() 和 writeLoop() 就已经开始执行了,它会重复读取 reqch 中的内容,然后通过对应的 requestMethodKey 找到对应的 Response,最后通过 responseAndErr 这个 chanle 返回给主 gorountine。
writeLoop()

writeLoop() 则是通过 writech 获得 request 然后使用 早就创建好的 writer 进行传输,返回的错误会通过 writeErrCh 传回主 gorounite 。
主线程中也会通过 select 监听着 writeErrCh 还有 resc 两个 channel ,如果有 response 返回或者 err 不为空都会直接退出。
select {case err := <-writeErrCh:if debugRoundTrip {req.logf("writeErrCh resv: %T/%#v", err, err)}if err != nil {pc.close(fmt.Errorf("write error: %v", err))return nil, pc.mapRoundTripError(req, startBytesWritten, err)}if d := pc.t.ResponseHeaderTimeout; d > 0 {if debugRoundTrip {req.logf("starting timer for %v", d)}timer := time.NewTimer(d)defer timer.Stop() // prevent leaksrespHeaderTimer = timer.C}case re := <-resc:if (re.res == nil) == (re.err == nil) {panic(fmt.Sprintf("internal error: exactly one of res or err should be set; nil=%v", re.res == nil))}if debugRoundTrip {req.logf("resc recv: %p, %T/%#v", re.res, re.err, re.err)}if re.err != nil {return nil, pc.mapRoundTripError(req, startBytesWritten, re.err)}return re.res, nil}
