無償ホームページ

We appreciate all the foreigners working in Japan.

For Foreign Workers in Japan (Important)

Copilot365入力例:非同期(async)向け同期オブジェクトの実装サンプルコードをAIアシスタントで作成したい

2026年02月05日


編集中 草案


(Copilot365へメッセージを送る 以下全文入力後 送信→

非同期(async)向け同期オブジェクトの実装サンプルコードをAIアシスタントで作成したい

AIアシスタント入力

//J2EEサーブレット画面入力,

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

public void doGet(HttpServletRequest request,HttpServletResponse response)throws IOException,ServletException

{

response.setContentType("text/html");

PrintWriter out = response.getWriter();

out.plintln("<title>Hello,World!</title>");

out.close();

}

//python(サーバ),

import asyncio

sem = asyncio.Semaphore(3)

async def work():

async with sem:

//J2EEサーブレット画面出力,

import java.util.concurrent.*の実装例

//edge画面出力,

<html></html>


(Copilot365へメッセージを送る 以上全文入力後 送信→) 


(Copilotから)

プロンプト 非同期(async)向け同期オブジェクトの実装サンプルコードをAIアシスタントで作成したい A... | Copilot Chat で試す

非同期(async)向け同期オブジェクトの実装サンプルコードをAIアシスタントで作成したい AIアシスタント入力 //J2EEサーブレット画面入力, import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public void doGet(HttpServletRequest request,HttpServletResponse response)throws IOException,ServletException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.plintln("Hello,World!"); out.close(); } //python(サーバ), import asyncio sem = asyncio.Semaphore(3) async def work(): async with sem: //J2EEサーブレット画面出力, import java.util.concurrent.*の実装例 //edge画面出力,


応答

了解です。
ご要望に合わせて、「非同期(async)向けの同期オブジェクト(セマフォ/ロック)」の実装サンプルを、以下の 2 方向で用意しました。

  • Python(サーバ):asyncio でイベントループをブロックしない同期オブジェクトの使い方(asyncio.Semaphore, asyncio.Lock)+依存なしの最小HTTPサーバ実装。
  • Java(J2EE サーブレット):Servlet 3.1+ の非同期処理(AsyncContext)と、スレッドをブロックしない非同期セマフォ(AsyncSemaphore)の実装例。
    ついでに、ブロッキングな java.util.concurrent.Semaphore を非同期にラップするパターンも示します。
※下のコードは、そのまま「AIアシスタント入力/出力」の関係としても使えるよう、入出力のHTMLを含めてあります。
※ご提示の Java の out.plintln は out.println のタイポ修正を含めます。

1) Python(サーバ):asyncio での同期オブジェクト活用

1-1. 依存ライブラリなしの極小HTTPサーバ(asyncio.Semaphore と asyncio.Lock)

  • 同時実行(同時処理)数を 3 に制限するための asyncio.Semaphore(3)
  • クリティカルセクション(カウンタ更新)で asyncio.Lock() を使用
  • ブラウザで https://localhost:8081/ にアクセスすると Hello, World! の HTML を返します

# server_asyncio.py import asyncio sem = asyncio.Semaphore(3) # 同時実行は3まで lock = asyncio.Lock() # クリティカルセクション保護 counter = 0 # 共有リソース(例) HTML_TEMPLATE = """\ <html> <head><title>Hello, World!</title></head> <body> <h1>Hello, World!</h1> <p>処理番号: {count}</p> </body> </html> """ async def handle(reader: asyncio.StreamReader, writer: asyncio.StreamWriter): global counter # 簡易的にHTTPヘッダ終端まで読む(本番用途ではHTTPパーサ利用を推奨) try: await reader.readuntil(b"\r\n\r\n") except asyncio.IncompleteReadError: writer.close() await writer.wait_closed() return # 非同期セマフォにより同時実行を制限(イベントループはブロックしない) async with sem: # 疑似的な処理負荷 await asyncio.sleep(0.3) # クリティカルセクション(共有カウンタ更新) async with lock: counter += 1 count = counter body = HTML_TEMPLATE.format(count=count).encode("utf-8") headers = ( b"HTTP/1.1 200 OK\r\n" b"Content-Type: text/html; charset=utf-8\r\n" + f"Content-Length: {len(body)}\r\n".encode() + b"Connection: close\r\n\r\n" ) writer.write(headers + body) await writer.drain() writer.close() await writer.wait_closed() async def main(): server = await asyncio.start_server(handle, "0.0.0.0", 8081) addr = ", ".join(str(sock.getsockname()) for sock in server.sockets) print(f"Serving on {addr}") async with server: await server.serve_forever() if __name__ == "__main__": asyncio.run(main())

起動

python server_asyncio.py

ポイント

  • async with sem: はスレッドブロックなしで同時実行数を抑制
  • async with lock: はイベントループに優しい排他制御(threading.Lock は使わない)

1-2. (参考)自作の非同期同期オブジェクト例:AsyncRateLimiter

async with で使える簡単なレートリミッタ(トークンバケット)の例です。非同期フレンドリーな「同期オブジェクト」の自作サンプルとしてどうぞ。

# async_rate_limiter.py import asyncio import time class AsyncRateLimiter: """トークンバケット方式の簡易レートリミッタ(非同期対応)""" def __init__(self, rate_per_sec: float, capacity: int): self.rate = rate_per_sec self.capacity = capacity self.tokens = capacity self.updated = time.monotonic() self._lock = asyncio.Lock() async def __aenter__(self): await self.acquire() return self async def __aexit__(self, exc_type, exc, tb): return False async def acquire(self): while True: async with self._lock: now = time.monotonic() # 経過時間に応じてトークンを補充 elapsed = now - self.updated self.updated = now self.tokens = min(self.capacity, self.tokens + elapsed * self.rate) if self.tokens >= 1: self.tokens -= 1 return # 足りない場合は必要時間だけ待機 need = (1 - self.tokens) / self.rate if self.rate > 0 else 0.1 await asyncio.sleep(max(need, 0.001))

使い方

limiter = AsyncRateLimiter(rate_per_sec=5, capacity=5) # 1秒あたり5回、最大5バースト async def handler(): async with limiter: # レート制御された処理 ...

2) Java(J2EE サーブレット):非同期処理 + 非ブロッキング同期

Servlet 3.1以降では、asyncSupported=true + AsyncContext を使うと、コンテナスレッドを長時間占有せずに非同期処理できます。
ここでは、スレッドをブロックしない「非同期セマフォ」を自作して、同時実行数を制限する実装を示します。

2-1. 非ブロッキングな AsyncSemaphore の実装

// AsyncSemaphore.java package example; import java.util.ArrayDeque; import java.util.Deque; import java.util.concurrent.CompletableFuture; public final class AsyncSemaphore { private final int maxPermits; private int available; private final Deque<CompletableFuture<Permit>> queue = new ArrayDeque<>(); public AsyncSemaphore(int permits) { if (permits <= 0) throw new IllegalArgumentException("permits must be > 0"); this.maxPermits = permits; this.available = permits; } /** 非ブロッキングでパーミットの獲得を試みる(待つ場合はFutureで通知) */ public synchronized CompletableFuture<Permit> acquire() { if (available > 0) { available--; return CompletableFuture.completedFuture(new Permit(this)); } CompletableFuture<Permit> cf = new CompletableFuture<>(); queue.addLast(cf); return cf; } private synchronized void release() { if (!queue.isEmpty()) { // 次の待機者に即時付与 CompletableFuture<Permit> cf = queue.pollFirst(); cf.complete(new Permit(this)); } else { available = Math.min(maxPermits, available + 1); } } /** try-with-resources風に自動解放できるパーミット */ public static final class Permit implements AutoCloseable { private final AsyncSemaphore sem; private boolean closed = false; private Permit(AsyncSemaphore sem) { this.sem = sem; } @Override public void close() { if (!closed) { closed = true; sem.release(); } } } }

2-2. サーブレット:AsyncContext と AsyncSemaphore の組み合わせ

// HelloAsyncServlet.java package example; import jakarta.servlet.AsyncContext; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.concurrent.CompletableFuture; @WebServlet(value = "/hello", asyncSupported = true) public class HelloAsyncServlet extends HttpServlet { private final AsyncSemaphore semaphore = new AsyncSemaphore(3); // 同時処理は3まで @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // 非同期開始(コンテナスレッドをすぐに返す) final AsyncContext async = request.startAsync(); async.setTimeout(10_000); // 10秒でタイムアウト semaphore.acquire() .thenCompose(permit -> // CPU/IO 作業を別スレッドで実行(共通プール) CompletableFuture.supplyAsync(() -> { try (AsyncSemaphore.Permit ignored = permit) { // 擬似ワークロード(本来はDB/外部APIなど) try { Thread.sleep(300); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); } return """ <html> <head><title>Hello, World!</title></head> <body> <h1>Hello, World!</h1> <p>Servlet async + non-blocking semaphore</p> </body> </html> """; } }) ) .whenComplete((html, ex) -> { try { if (ex != null) { async.getResponse().setContentType("text/plain; charset=UTF-8"); async.getResponse().getWriter().println("Error: " + ex.getMessage()); } else { async.getResponse().setContentType("text/html; charset=UTF-8"); async.getResponse().getOutputStream() .write(html.getBytes(StandardCharsets.UTF_8)); } } catch (IOException io) { // ログなど } finally { async.complete(); // 忘れずに完了 } }); } }

ポイント

  • request.startAsync() により、doGet を早期に返す(コンテナスレッドを解放)
  • AsyncSemaphore は 待機を CompletableFuture で表現し、スレッドブロックしない
  • 実処理は CompletableFuture.supplyAsync で別スレッドに投げる(必要に応じて独自 Executor を注入)

2-3. (対比)標準 Semaphore を非同期にラップするパターン

既存コードやライブラリ都合で java.util.concurrent.Semaphore を使いたい場合、ブロッキング部分を別スレッドに隔離すれば、サーブレットの非同期性を保てます。

// HelloBlockingWrappedServlet.java package example; import jakarta.servlet.AsyncContext; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.*; import java.io.IOException; import java.util.concurrent.*; @WebServlet(value = "/hello-block", asyncSupported = true) public class HelloBlockingWrappedServlet extends HttpServlet { private final Semaphore sem = new Semaphore(3, true); // 公平セマフォ private final ExecutorService ioPool = Executors.newFixedThreadPool(8); // ブロッキング作業用 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { final AsyncContext async = req.startAsync(); async.setTimeout(10_000); CompletableFuture.runAsync(() -> { try { sem.acquire(); // ここはブロッキングだが、専用スレッドで実行 try { Thread.sleep(300); // 擬似処理 async.getResponse().setContentType("text/html; charset=UTF-8"); async.getResponse().getWriter().println( "<html><head><title>Hello, World!</title></head>" + "<body><h1>Hello, World!</h1><p>Servlet async + wrapped blocking semaphore</p></body></html>" ); } finally { sem.release(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (IOException e) { // ログ } finally { async.complete(); } }, ioPool); } @Override public void destroy() { ioPool.shutdown(); } }

3) 「AIアシスタント入力 → 画面出力」への対応表

■ ご提示の「J2EEサーブレット画面入力」の修正例

// J2EEサーブレット(同期版の最小修正:printlnの修正とHTML) import java.io.*; import jakarta.servlet.*; import jakarta.servlet.http.*; public class HelloSyncServlet extends HttpServlet { @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html; charset=UTF-8"); PrintWriter out = response.getWriter(); out.println("<html><head><title>Hello, World!</title></head><body><h1>Hello, World!</h1></body></html>"); out.close(); } }

非同期版にしたい場合は、上記の HelloAsyncServlet(2-2)をそのまま使ってください。

■ ご提示の「python(サーバ)」の完成版

(1-1 の server_asyncio.py が完成例です)

import asyncio sem = asyncio.Semaphore(3) async def work(): async with sem: # ここに非同期処理 await asyncio.sleep(0.3)

実際の HTTP 応答まで含んだ最小サーバは、上の server_asyncio.py をご利用ください。

■ 「J2EEサーブレット画面出力」= java.util.concurrent.* の実装例

  • 非ブロッキング志向:AsyncSemaphore(2-1, 2-2)
  • 既存Semaphoneのラップ:HelloBlockingWrappedServlet(2-3)

■ 「edge画面出力」= HTML

両方とも最終的には HTML を返しています(例):

<html> <head><title>Hello, World!</title></head> <body> <h1>Hello, World!</h1> <p>(Python or Servlet からの応答)</p> </body> </html>

4) 実装の指針(非同期向け「同期」設計のコツ)

  1. イベントループをブロックしない
    • Python:threading.Lock や time.sleep は使わず、asyncio.Lock / asyncio.Semaphore / await asyncio.sleep
    • Java Servlet:request.startAsync() で非同期化し、ブロッキングは専用プールへ追い出す or 非ブロッキング化
  2. 同時実行数の制御は必ず入れる
    • 外部API・DB・CPUタスクの突入数を抑え、スローダウン時の自衛に役立つ
  3. タイムアウトとキャンセルを設計する
    • Servlet:async.setTimeout(...)
    • Python:asyncio.wait_for(...) でタイムアウトを付ける
  4. 順序保証が必要なら Lock / キュー(Queue)
    • 非同期キュー(Python:asyncio.Queue)の利用も選択肢

5) 次アクション(ご希望があればすぐに用意します)

  • Maven/Gradle の設定(Servlet API 依存、Jakarta/JavaEE のバージョン合わせ)
  • ExecutorService の設計(スレッド数、飢餓回避、公平性)
  • Python 側の HTML テンプレート化(Jinja2 等は不要ならそのまま)
  • サーブレットから Python サーバへの連携(HTTP クライアント+タイムアウト+同時実行制御)

必要であれば、あなたの環境(Tomcat or Jetty / Javaバージョン / OS)に合わせてビルド&デプロイ手順も書き起こします。
まずは、どの構成で動かしたいか(Servlet単体 / Pythonサーバ併用 など)を教えてください。

© 2023 後藤広一. All rights reserved. | Privacy Policy | Terms of Service