面试题答案
一键面试使用协程处理大量网络连接请求
- 选择合适的协程库:在Python中可使用
asyncio
库,在Go语言中有原生的goroutine
。以asyncio
为例,创建一个异步函数来处理每个网络连接请求,如:
import asyncio
async def handle_connection(reader, writer):
data = await reader.read(1024)
message = data.decode('utf - 8')
addr = writer.get_extra_info('peername')
print(f"Received {message!r} from {addr!r}")
writer.write(b'OK')
await writer.drain()
writer.close()
await writer.wait_closed()
- 启动协程监听连接:使用
asyncio.start_server
来启动一个服务器,将处理函数注册到事件循环中,如:
async def main():
server = await asyncio.start_server(
handle_connection, '127.0.0.1', 8888)
addr = server.sockets[0].getsockname()
print(f'Serving on {addr}')
async with server:
await server.serve_forever()
asyncio.run(main())
在Go语言中,使用net/http
包结合goroutine
处理请求:
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "OK")
}
func main() {
http.HandleFunc("/", handler)
fmt.Println("Serving on :8080")
http.ListenAndServe(":8080", nil)
}
每个新的HTTP请求都会由一个新的goroutine
来处理。
针对性能瓶颈的优化措施
- I/O阻塞优化
- 使用异步I/O操作:在
asyncio
中,await
关键字确保在执行I/O操作(如读取或写入网络数据)时,事件循环可以去执行其他可运行的协程,从而避免线程阻塞。在Go语言中,网络I/O操作默认是异步非阻塞的,goroutine
会在I/O操作等待时让出执行权。 - 优化I/O缓冲区:合理设置I/O缓冲区大小可以减少I/O操作的次数。例如在Python的
asyncio
中,通过调整reader
和writer
的缓冲区参数,在Go语言中,可通过bufio
包来优化I/O操作的缓冲区。
- 使用异步I/O操作:在
- 资源竞争优化
- 使用锁机制:当多个协程需要访问共享资源时,使用互斥锁(在Python中可使用
asyncio.Lock
,在Go语言中可使用sync.Mutex
)来保护共享资源。例如在Python中:
- 使用锁机制:当多个协程需要访问共享资源时,使用互斥锁(在Python中可使用
import asyncio
lock = asyncio.Lock()
shared_resource = 0
async def update_shared_resource():
global shared_resource
async with lock:
shared_resource += 1
在Go语言中:
package main
import (
"fmt"
"sync"
)
var (
sharedResource int
mutex sync.Mutex
)
func updateSharedResource() {
mutex.Lock()
sharedResource++
mutex.Unlock()
}
- **使用无锁数据结构**:对于一些高并发场景,可使用无锁数据结构(如在Go语言中,`sync.Map`是一个线程安全的无锁映射)来避免锁带来的性能开销。
- **减少共享资源**:尽量将数据封装在协程内部,避免不必要的共享,从而减少资源竞争的可能性。