pythonで単一のクライアントとソケット通信する場合もsocket.setblocking(0)は使うべきではないのでしょうか？


<https://docs.python.org/ja/3.5/howto/sockets.html>  
上記のサイトにsocket.setblocking(0)は使うべきではないと表記してありますが，単一のクライアントとのみ通信したい場合も使うべきではないのでしょうか？  
別のサイトでこのようなビジーループはCPUのメモリを多く使ってしまうという記述を見かけましたが，setblocking(0)を実際にサーバで

[code]

    soc=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    soc.bind(('127.0.0.1',65535))
    soc.listen(5)
    soc.setblocking(0)
    
[/code]

のようにして単一のクライアントと通信するために使ってみたのですが，CPU使用率は1％にも満たず，動作も問題ありませんでした．  
このような場合はsetblocking(0)を使ってもよいのでしょうか？




socket.setblocking(0)にして、send, recv, connect,
acceptで処理をすることを、<https://docs.python.org/ja/3.5/howto/sockets.html>では、「愚かな解法」と書かれています。ノンブロッキングソケットをsoc.recv()等を使って、効率的な処理をできるようなプログラムを自分で書くのは相当な手間だと思います。単一のクライアントとのみ通信すると限定してしまえば、プログラムを書くのは簡単になりますが、ノンブロッキングソケットを使うメッリトはないと思います。それであれば、ブロッキングソケットで十分だと思います。

ネットワークでのやり取りが増加している現在では、node.jsだと最初から非同期プログラミングが前提となっているように、効率的に処理をするためにノンブロッキングソケットを使うことは多くなってきています。Pythonでは以前からselectを使えたし、最近では`asyncio`モジュールがPython3.4で追加され、その後改善されてきています。もし、必要であればそれらを使えば問題はありません。

以下が公式ドキュメントの「[19.5. asyncio — Asynchronous I/O, event loop, coroutines and
tasks](https://docs.python.org/3.7/library/asyncio-stream.html#tcp-echo-
server-using-streams)」にあるTCP echo サーバーの例です。随分楽に書けるようになっています。

[code]

    import asyncio
    
    async def handle_echo(reader, writer):
        data = await reader.read(100)
        message = data.decode()
        addr = writer.get_extra_info('peername')
        print("Received %r from %r" % (message, addr))
    
        print("Send: %r" % message)
        writer.write(data)
        await writer.drain()
    
        print("Close the client socket")
        writer.close()
    
    loop = asyncio.get_event_loop()
    coro = asyncio.start_server(handle_echo, '127.0.0.1', 8888, loop=loop)
    server = loop.run_until_complete(coro)
    
    # Serve requests until Ctrl+C is pressed
    print('Serving on {}'.format(server.sockets[0].getsockname()))
    try:
        loop.run_forever()
    except KeyboardInterrupt:
        pass
    
    # Close the server
    server.close()
    loop.run_until_complete(server.wait_closed())
    loop.close()
    
[/code]




そのページで「愚かな解法」と書いてあるのは、ノンブロッキングについてでなく、ビジーループについてです。

質問のコードで、`soc.setblocking(0)` の後にどのようなコードが続くのか判りませんが、  
そこで、データの到着をループを繰り返す **以外** の方法(select 等)で待っているなら、  
それはビジーループではありません。

`soc` からデータが読み出せるまで何度も何度も何度も何度も `soc.recv()`
を繰り返すのがビジーループです。何度も何度も何度も何度も繰り返すので、当然 CPU 負荷は高くなります。

CPU 負荷が低いならビジーループになっていないのでしょうから、問題ありません。  
(ただし、ビジーループのはずなのに CPU 負荷が低いということなら、プログラムがあなたの意図した通りに動作していないということですが)

ノンブロッキングソケットは、select 等を使ってビジーループにならないように使えば、  
とても便利だと思います。避けないといけないようなものではありません。

