KnowHow

技術的なメモを中心にまとめます。
検索にて調べることができます。

非同期モデルについて(Python)

登録日 :2025/06/07 13:35
カテゴリ :Python基礎

ピザの注文を受け付けるピザーサーバを題材に並列処理を学ぶ。
asyncioを用いた、非同期処理サーバのサンプルコード

"""
Chapter12 / asynchronous_pizza / aio.py
"""
import asyncio
import socket
import time


class Kitchen:
    @staticmethod
    def cook_pizza(n):
        print(f"Started Cooking {n} pizzas!")
        time.sleep(n)
        print(f"Fresh {n} pizzas are ready!")


BUFFER_SIZE = 1024
ADDRESS = ('127.0.0.1', 12345)


class Server:
    def __init__(self, event_loop: asyncio.AbstractEventLoop) -> None:
        self.event_loop = event_loop
        print(f"Starting up at: {ADDRESS}")
        self.server_soket = socket.create_server(ADDRESS)
        self.server_soket.setblocking(False)

    async def start(self) -> None:
        """
        async:関数が非同期であることを示す
        """
        print("Server listening for incoming connections")
        try:
            while True:
                """
                await: コルーチンが完了するのを待つ間、他のタスクができるようにする
                """
                conn, client_address = await self.event_loop.sock_accept(
                    self.server_soket)
                self.event_loop.create_task(self.serve(conn))
        except Exception:
            self.server_soket.close()
            print("Server stopped.")

    async def serve(self, conn):
        while True:
            data = await self.event_loop.sock_recv(conn, BUFFER_SIZE)
            if not data:
                break
            try:
                order = int(data.decode())
                response = f"Thank you for ordering {order} pizzas!¥n"
                print(f"Sending messages to {conn.getpeername()}")
                await self.event_loop.sock_sendall(conn, f"{response}".encode())
                await self.event_loop.run_in_executor(None, Kitchen.cook_pizza, order)
                response = f"Your order of {order} pizzas is ready!¥n"
            except ValueError:
                response = "Wrong number of pizzas, please try again.¥n"

            print(f"Sending message to {conn.getpeername()}")
            await self.event_loop.sock_sendall(conn, response.encode())
        print(f"Connection with {conn.getpeername()} has been closed")
        conn.close()


if __name__ == "__main__":
    event_loop = asyncio.get_event_loop()
    server = Server(event_loop=event_loop)
    event_loop.create_task(server.start())
    event_loop.run_forever()