株式投資は少額投資(管理)が先、薄利多売や配当は後

When it comes to stock investing, start with small investments (management) first, and focus on small profits from high volume or dividends later.

毎日必ず寝て、夢の中で起こることは忘れましょう。

Make sure to sleep every day and forget what happens in your dreams.

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サーバ併用 など)を教えてください。

Share

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