<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title><![CDATA[Ao Li - Elasticsearch Labs]]></title>
    <description><![CDATA[Articles and tutorials from the Search team at Elastic]]></description>
    <copyright><![CDATA[© 2026. Elasticsearch B.V. All Rights Reserved]]></copyright>
    <image>
      <title><![CDATA[Ao Li - Elasticsearch Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1121c0bf0e8a6e65/6a88da6340a1841030ef456f/search-labs-thumbnail.png</url>
      <link>https://www.elastic.co/jp/search-labs/author/ao-li</link>
    </image>
    <link>https://www.elastic.co/jp/search-labs/author/ao-li</link>
    <atom:link href="https://www.elastic.co/jp/search-labs/rss/author/ao-li.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[jp]]></language>
    <lastBuildDate>Mon, 28 Sep 2026 04:51:14 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Lucene の同時実行バグ: 楽観的同時実行の失敗を修正する方法]]></title>
    <description><![CDATA[CMUのPASTAラボの決定論的並行性テストフレームワークであるFrayのおかげで、私たちはLuceneの厄介なバグを追跡し、それを潰すことができました。]]></description>
    <content:encoded><![CDATA[<p>はい、またバグ修正のブログです。しかし、この事件には意外な展開があり、オープンソースのヒーローが飛び込んできて事態を収拾するのです。 </p><p>並行性のバグをデバッグするのは簡単ではありませんが、ここで取り上げます。CMU の PASTA ラボによる決定論的同時実行テスト フレームワークである Fray は、不安定な障害を確実に再現可能な障害に変えます。Fray の巧妙なシャドウ ロック設計と正確なスレッド制御のおかげで、私たちは厄介な Lucene のバグを追跡し、ついにそれを撲滅することができました。この投稿では、オープンソースのヒーローとツールが、並行処理のデバッグの負担を軽減し、ソフトウェアの世界を大きく改善している仕組みについて説明します。</p><h2>並行性バグ：ソフトウェアエンジニアの悩みの種</h2><p>同時実行バグは最悪です。修正が難しいだけでなく、確実に故障させること自体が最も難しい部分です。このテストの失敗<a href="https://github.com/apache/lucene/issues/13127"><code>TestIDVersionPostingsFormat#testGlobalVersions</code></a>を例に挙げます。これは複数のドキュメント書き込みおよび更新スレッドを生成し、Lucene の楽観的同時実行モデルに挑戦します。このテストでは、楽観的同時実行制御における競合状態が明らかになりました。つまり、ドキュメント操作は、一連の操作の中で最新のものであると誤って主張する可能性があります😱。つまり、特定の状況では、楽観的同時実行制約により失敗するはずの更新または削除操作が実際には成功する可能性があります。</p><p></p>org.apache.lucene.sandbox.codecs.idversion.TestIDVersionPostingsFormat &gt; testGlobalVersions FAILED
    java.lang.AssertionError: maxSeqNo must be greater or equal to 7442 but was 7441
        at __randomizedtesting.SeedInfo.seed([B97A2BDBC7E40BF6:B4D76006D5101E6]:0)
        at org.apache.lucene.core@10.0.0-SNAPSHOT/org.apache.lucene.index.DocumentsWriterDeleteQueue.close(DocumentsWriterDeleteQueue.java:325)
        at org.apache.lucene.core@10.0.0-SNAPSHOT/org.apache.lucene.index.DocumentsWriter.flushAllThreads(DocumentsWriter.java:659)
        at org.apache.lucene.core@10.0.0-SNAPSHOT/org.apache.lucene.index.IndexWriter.getReader(IndexWriter.java:576)
        at org.apache.lucene.core@10.0.0-SNAPSHOT/org.apache.lucene.index.StandardDirectoryReader.doOpenFromWriter(StandardDirectoryReader.java:381)
        at org.apache.lucene.core@10.0.0-SNAPSHOT/org.apache.lucene.index.StandardDirectoryReader.doOpenIfChanged(StandardDirectoryReader.java:355)
        at org.apache.lucene.core@10.0.0-SNAPSHOT/org.apache.lucene.index.StandardDirectoryReader.doOpenIfChanged(StandardDirectoryReader.java:345)
        at org.apache.lucene.core@10.0.0-SNAPSHOT/org.apache.lucene.index.DirectoryReader.openIfChanged(DirectoryReader.java:170)
        at org.apache.lucene.core@10.0.0-SNAPSHOT/org.apache.lucene.search.SearcherManager.refreshIfNeeded(SearcherManager.java:144)
        at org.apache.lucene.core@10.0.0-SNAPSHOT/org.apache.lucene.search.SearcherManager.refreshIfNeeded(SearcherManager.java:52)
        at org.apache.lucene.core@10.0.0-SNAPSHOT/org.apache.lucene.search.ReferenceManager.doMaybeRefresh(ReferenceManager.java:167)
        at org.apache.lucene.core@10.0.0-SNAPSHOT/org.apache.lucene.search.ReferenceManager.maybeRefresh(ReferenceManager.java:213)<p>Java スタック トレースが嫌いな方には申し訳ありません。注意: 削除は必ずしも「削除」を意味するわけではありません。Lucene のセグメントは読み取り専用であるため、ドキュメントの「更新」を示すこともできます。
</p><p>Apache Lucene は、 <a href="https://github.com/apache/lucene/blob/f2e7ae40af0b28b1d5f2edc31f8858229a8523f4/lucene/core/src/java/org/apache/lucene/index/DocumentsWriter.java"><code>DocumentsWriter</code></a>クラスを通じてドキュメントを書き込む各スレッドを管理します。このクラスはドキュメント書き込み用のスレッドを作成または再利用し、各書き込みアクションは<a href="https://github.com/apache/lucene/blob/f2e7ae40af0b28b1d5f2edc31f8858229a8523f4/lucene/core/src/java/org/apache/lucene/index/DocumentsWriterPerThread.java"><code>DocumentsWriterPerThread</code></a> (DWPT) クラス内でその情報を制御します。さらに、ライターは<a href="https://github.com/apache/lucene/blob/f2e7ae40af0b28b1d5f2edc31f8858229a8523f4/lucene/core/src/java/org/apache/lucene/index/DocumentsWriterDeleteQueue.java"><code>DocumentsWriterDeleteQueue</code></a> (DWDQ) で削除されたドキュメントを追跡します。これらの構造は、すべてのドキュメント変更アクションをメモリ内に保持し、定期的にフラッシュしてメモリ内のリソースを解放し、構造をディスクに保持します。</p><p></p><p><a href="https://en.wikipedia.org/wiki/Blocking_(computing)">スレッドのブロックを</a>防ぎ、並行システムでの高いスループットを確保するために、Apache Lucene は非常に重要なセクションのみで<a href="https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html">同期</a>を試みます。これは実際には良いことですが、他の並行システムと同様に、問題が存在します。</p><h2>
偽りの希望</h2><p>最初の調査で、適切に同期されていない重要なセクションがいくつか見つかりました。特定の<a href="https://github.com/apache/lucene/blob/f2e7ae40af0b28b1d5f2edc31f8858229a8523f4/lucene/core/src/java/org/apache/lucene/index/DocumentsWriterDeleteQueue.java"><code>DocumentsWriterDeleteQueue</code></a>に対するすべてのやり取りは、それを囲む<a href="https://github.com/apache/lucene/blob/f2e7ae40af0b28b1d5f2edc31f8858229a8523f4/lucene/core/src/java/org/apache/lucene/index/DocumentsWriter.java"><code>DocumentsWriter</code></a>によって制御されます。したがって、個々のメソッドは<a href="https://github.com/apache/lucene/blob/f2e7ae40af0b28b1d5f2edc31f8858229a8523f4/lucene/core/src/java/org/apache/lucene/index/DocumentsWriterDeleteQueue.java"><code>DocumentsWriterDeleteQueue</code></a>内で適切に同期されない可能性がありますが、そのメソッドの世界へのアクセスは適切に同期されます (または同期される必要があります)。(所有権とアクセスがどのように混乱するかについては深く考えないことにします。これは、多くの貢献者によって書かれた長期にわたるプロジェクトです。少しは余裕を持ってください。</p><p></p><p>しかし、<a href="https://github.com/apache/lucene/blob/40060f8b7080d06a218518445a0a1dfc520c812a/lucene/core/src/java/org/apache/lucene/index/DocumentsWriterFlushControl.java#L572-L576">フラッシュ中に同期されていない場所が 1 か所</a>見つかりました。</p>// Advance the queue, meaning create a new one to keep track of deletes
// Since we have been flushed, let's starting tracking again
DocumentsWriterDeleteQueue newQueue = documentsWriter.deleteQueue.advanceQueue(perThreadPool.size());
// OK, get the current new maximum sequence number for optimistic concurrency
seqNo = documentsWriter.deleteQueue.getMaxSeqNo();
// Reset to the new queue
documentsWriter.resetDeleteQueue(newQueue);<p>これらのアクションは、単一のアトミック操作に同期されません。つまり、 <code>newQueue</code>が作成されてから<code>getMaxSeqNo</code>が呼び出されるまでの間に、 <code>documentsWriter</code>クラス内のシーケンス番号を増分する他のコードが実行された可能性があります。バグを見つけました!</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltbc55033280b45913/6a1706b4dc55dec27fe00d30/3f2617a102d28735e755a7539b047c28beda41be-1600x453.jpg" alt="" /><p>
しかし、ほとんどの複雑なバグと同様に、根本原因を見つけるのは簡単ではありませんでした。その時、英雄が登場した。</p><h2>戦いの英雄</h2><p>私たちのヒーロー、PASTA ラボの<a href="https://aoli.al/">Ao Li</a>と彼の同僚の登場です。フレイでどうやって彼らが危機を救ったのか、彼に説明してもらいましょう。</p><p><a href="https://github.com/cmu-pasta/fray">Fray は</a>、カーネギーメロン大学の<a href="https://pastalab.org/">PASTA ラボ</a>の研究者によって開発された決定論的並行性テスト フレームワークです。Fray 構築の背後にある動機は、学界と業界の間にある顕著なギャップに起因しています。決定論的並行性テストは学術研究において 20 年以上にわたって広範に研究されてきましたが、実践者は並行プログラムをテストするために、信頼性が低く不安定であると広く認識されている方法であるストレス テストに依然頼っています。したがって、私たちは、一般性と実用性を主な目標として、決定論的な同時実行テスト フレームワークを設計および実装したいと考えました。</p><p></p><h2>核となるアイデア</h2><p>Fray は、本質的に、シンプルでありながら強力な原則である「順次実行」を活用します。Java の並行性モデルは重要な<a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4.3">特性</a>を提供します。プログラムにデータ競合がない場合、すべての実行は順次一貫しているように見えます。これは、プログラムの動作を一連のプログラム ステートメントとして表現できることを意味します。</p><p>Fray は、ターゲット プログラムを順次実行することで動作します。各ステップで、1 つを除くすべてのスレッドを一時停止し、スレッドのスケジュールを正確に制御できるようにします。同時実行をシミュレートするためにスレッドはランダムに選択されますが、選択内容は後続の確定的な再生のために記録されます。実行を最適化するために、Fray は、スレッドがロックやアトミック/揮発性アクセスなどの同期命令を実行しようとしているときにのみコンテキストスイッチを実行します。データ競合の自由に関する優れた特性は、この限定されたコンテキスト切り替えが、あらゆるスレッドインターリーブによるすべての観察可能な動作を調査するのに十分であるということです (<a href="https://arxiv.org/abs/2501.12618">私たちの論文に</a>は証明の概要があります)。</p><p></p><h2>課題: スレッドのスケジュール制御</h2><p>中心となるアイデアはシンプルに見えますが、Fray の実装には大きな課題がありました。スレッドのスケジュールを制御するには、Fray は各アプリケーション スレッドの実行を管理する必要があります。一見すると、同時実行プリミティブをカスタマイズされた実装に置き換えるという単純なことのように思えるかもしれません。ただし、JVM での同時実行制御は複雑であり、<a href="https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-6.html">バイトコード命令</a>、<a href="https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/concurrent/locks/ReentrantLock.html">高レベルライブラリ</a>、<a href="https://github.com/openjdk/jdk/blob/b720517cb33c2119ec6ed85504bce321de748228/src/java.base/share/classes/java/lang/Object.java#L394">ネイティブメソッド</a>が混在します。</p><p></p><p>これはウサギの穴であることが判明しました:</p><p></p><ul><li><p>たとえば、すべての<code>MONITORENTER</code>命令には、同じメソッド内に対応する<code>MONITOREXIT</code>が必要です。Fray が<code>MONITORENTER</code>スタブ/モックへのメソッド呼び出しに置き換える場合は、 <code>MONITOREXIT</code>置き換える必要があります。</p></li><li><p><code>object.wait/notify</code>を使用するコードでは、 <code>MONITORENTER</code>が置き換えられる場合、対応する<code>object.wait</code>も置き換えられる必要があります。この置換チェーンは<code>object.notify</code>以降まで拡張されます。</p></li><li><p>JVM は、ネイティブ コード内で特定の並行性関連のメソッド (たとえば、スレッドが終了すると<code>object.notify</code> ) を呼び出します。これらの操作を置き換えるには、JVM 自体を変更する必要があります。</p></li><li><p>クラス ローダーやガベージ コレクション (GC) スレッドなどの JVM 機能でも、同時実行プリミティブが使用されます。これらのプリミティブを変更すると、JVM 機能との不一致が生じる可能性があります。</p></li><li><p>JDK で並行性プリミティブを置き換えると、初期化フェーズで JVM がクラッシュすることがよくあります。</p></li></ul><p></p><p>これらの課題により、並行性プリミティブを包括的に置き換えることは不可能であることが明らかになりました。</p><h2>
私たちの解決策：シャドウロック設計</h2><p>これらの課題に対処するために、Fray は、同時実行プリミティブを置き換えることなくスレッド実行を調整するための新しいシャドウ ロック メカニズムを使用します。シャドウ ロックは、スレッドの実行をガイドする仲介者として機能します。たとえば、ロックを取得する前に、アプリケーション スレッドは対応するシャドウ ロックと対話する必要があります。シャドウ ロックは、スレッドがロックを取得できるかどうかを決定します。スレッドが続行できない場合、シャドウ ロックによってそのスレッドがブロックされ、他のスレッドの実行が許可されるため、デッドロックが回避され、同時実行が制御されます。この設計により、Fray は並行性セマンティクスの正確性を維持しながら、スレッドインターリーブを透過的に制御できます。各同時実行プリミティブは、健全性と完全性を確保するために、シャドウ ロック フレームワーク内で慎重にモデル化されます。より詳しい技術的な詳細については、当社の論文をご覧ください。</p><p></p><p>さらに、この設計は将来を見据えたものとなっています。同時実行プリミティブの周囲にシャドウ ロックのインストルメンテーションのみを必要とするため、新しいバージョンの JVM との互換性が確保されます。これは、JVM の並行性プリミティブのインターフェースが比較的安定しており、長年にわたって変更されていないため実現可能です。</p><h2>
テストの乱闘</h2><p>Fray を構築した後、次のステップは評価でした。幸いなことに、Apache Lucene などの多くのアプリケーションには、すでに同時実行テストが含まれています。このような同時実行テストは、複数のスレッドを生成し、何らかの作業を実行し、その後 (通常は) それらのスレッドが終了するまで待機し、何らかのプロパティをアサートする通常の JUnit テストです。ほとんどの場合、これらのテストは 1 つのインターリーブのみを実行するため合格します。さらに悪いことに、前述のように、一部のテストは CI/CD 環境でたまにしか失敗しないため、これらの失敗をデバッグするのは非常に困難です。同じテストを Fray で実行したところ、多数のバグが発見されました。特に、Fray は、このブログの焦点である<a href="https://github.com/apache/lucene/issues/13127"><code>TestIDVersionPostingsFormat.testGlobalVersions</code></a>を含め、信頼できる再現がないため未修正のまま残っていた、以前に報告されたバグを再発見しました。幸いなことに、Fray を使用すると、それらを確定的に再生して開発者に詳細な情報を提供できるため、問題を確実に再現して修正することができます。</p><p></p><h2>フレイの次のステップ</h2><p>Elastic の開発者から、Fray が並行性バグのデバッグに役立ったという話を聞き、大変嬉しく思っています。私たちは、より多くの開発者が Fray を利用できるようにするために、引き続き取り組んでいきます。</p><p>私たちの短期的な目標には、乱数ジェネレータや<code>object.hashcode</code>の使用など、他の非決定論的な操作が存在する場合でも、スケジュールを決定論的に再生する Fray の機能を強化することが含まれます。また、Fray の使いやすさを向上させ、開発者が手動介入なしに既存の同時実行テストを分析およびデバッグできるようにすることを目指しています。最も重要なことは、プログラム内の同時実行の問題のデバッグやテストで課題に直面している場合は、ぜひご連絡ください。遠慮なく、 <a href="https://github.com/cmu-pasta/fray">Fray Github リポジトリ</a>に問題を投稿してください。</p><p></p><h2>同時実行バグを修正する時間</h2><p>Ao Li と PASTA ラボのおかげで、このテストが確実に失敗するインスタンスができました。ついにこの問題を解決できます。重要な問題は、 <a href="https://github.com/apache/lucene/blob/f2e7ae40af0b28b1d5f2edc31f8858229a8523f4/lucene/core/src/java/org/apache/lucene/index/DocumentsWriterPerThreadPool.java"><code>DocumentsWriterPerThreadPool</code></a>スレッドとリソースの再利用をどのように許可するかにありました。</p>1&gt; new Writer: DocumentsWriterPerThread [pendingDeletes=gen=0, segment=_0, aborted=false, numDocsInRAM=0, deleteQueue=DWDQ: [ generation: 0 ], 0 deleted docIds]
1&gt; DWDQ: [ generation: 0 ] id: 245403753 tid: t0 20 getNextSequenceNumber 1 called from stack:
&lt;snip&gt;...&lt;/snip&gt;
1&gt; new Writer: DocumentsWriterPerThread [pendingDeletes=gen=0, segment=_1, aborted=false, numDocsInRAM=0, deleteQueue=DWDQ: [ generation: 0 ], 0 deleted docIds]
1&gt; new Writer: DocumentsWriterPerThread [pendingDeletes=gen=0, segment=_5, aborted=false, numDocsInRAM=0, deleteQueue=DWDQ: [ generation: 0 ], 0 deleted docIds]
1&gt; new Writer: DocumentsWriterPerThread [pendingDeletes=gen=0, segment=_2, aborted=false, numDocsInRAM=0, deleteQueue=DWDQ: [ generation: 0 ], 0 deleted docIds]
1&gt; new Writer: DocumentsWriterPerThread [pendingDeletes=gen=0, segment=_6, aborted=false, numDocsInRAM=0, deleteQueue=DWDQ: [ generation: 0 ], 0 deleted docIds]
1&gt; new Writer: DocumentsWriterPerThread [pendingDeletes=gen=0, segment=_3, aborted=false, numDocsInRAM=0, deleteQueue=DWDQ: [ generation: 0 ], 0 deleted docIds]
1&gt; new Writer: DocumentsWriterPerThread [pendingDeletes=gen=0, segment=_4, aborted=false, numDocsInRAM=0, deleteQueue=DWDQ: [ generation: 0 ], 0 deleted docIds]<p>ここでは、世代 0 の初期削除キューを参照して各スレッドが作成されていることがわかります。</p><p>その後、フラッシュ時にキューの前進が発生し、キュー内の前の 7 つのアクションが正しく確認されます。</p>1&gt; DWDQ: [ generation: 0 ] id: 245403753 tid: t020 advanceQueue called from stack with maxSeq 9 lastSeqNo: 1 maxNumPendingOps: 7:
&lt;snip&gt;...&lt;/snip&gt;
1&gt; DWDQ: [ generation: 0 ] id: 245403753 tid: t525 getNextSequenceNumber 2 called from stack:
1&gt; DWDQ: [ generation: 0 ] id: 245403753 tid: t828 getNextSequenceNumber 3 called from stack:
1&gt; DWDQ: [ generation: 0 ] id: 245403753 tid: t727 getNextSequenceNumber 4 called from stack:
1&gt; DWDQ: [ generation: 0 ] id: 245403753 tid: t626 getNextSequenceNumber 5 called from stack:
1&gt; DWDQ: [ generation: 0 ] id: 245403753 tid: t424 getNextSequenceNumber 6 called from stack:
1&gt; DWDQ: [ generation: 0 ] id: 245403753 tid: t323 getNextSequenceNumber 7 called from stack:<p>しかし、すべてのスレッドがフラッシュを完了する前に、2 つのスレッドが追加のドキュメントに再利用されます。</p>1&gt; getAndLock: DocumentsWriterPerThread [pendingDeletes=gen=0, segment=_0, aborted=false, numDocsInRAM=1, deleteQueue=DWDQ: [ generation: 0 ], 0 deleted docIds]
1&gt; getAndLock: DocumentsWriterPerThread [pendingDeletes=gen=0, segment=_3, aborted=false, numDocsInRAM=1, deleteQueue=DWDQ: [ generation: 0 ], 0 deleted docIds]<p>これにより、 <code>seqNo</code>はフラッシュ時に7と計算された想定最大値を超えて増加します。セグメント<code>_3</code>と<code>numDocsInRAM</code>が追加されていることに注意してください。 <code>_0</code></p>1&gt; DocumentsWriterPerThread [pendingDeletes=gen=0, segment=_2, aborted=false, numDocsInRAM=1, deleteQueue=DWDQ: [ generation: 0 ], 0 deleted docIds] checkout to remove
1&gt; DocumentsWriterPerThread [pendingDeletes=gen=0, segment=_3, aborted=false, numDocsInRAM=2, deleteQueue=DWDQ: [ generation: 0 ], 0 deleted docIds] checkout to remove
1&gt; DocumentsWriterPerThread [pendingDeletes=gen=0, segment=_6, aborted=false, numDocsInRAM=1, deleteQueue=DWDQ: [ generation: 0 ], 0 deleted docIds] checkout to remove
1&gt; DocumentsWriterPerThread [pendingDeletes=gen=0, segment=_4, aborted=false, numDocsInRAM=1, deleteQueue=DWDQ: [ generation: 0 ], 0 deleted docIds] checkout to remove
1&gt; DocumentsWriterPerThread [pendingDeletes=gen=0, segment=_5, aborted=false, numDocsInRAM=1, deleteQueue=DWDQ: [ generation: 0 ], 0 deleted docIds] checkout to remove
1&gt; DocumentsWriterPerThread [pendingDeletes=gen=0, segment=_1, aborted=false, numDocsInRAM=1, deleteQueue=DWDQ: [ generation: 0 ], 0 deleted docIds] checkout to remove
1&gt; DocumentsWriterPerThread [pendingDeletes=gen=0, segment=_0, aborted=false, numDocsInRAM=2, deleteQueue=DWDQ: [ generation: 0 ], 0 deleted docIds] checkout to remove<p>その結果、Lucene はフラッシュ中のドキュメント アクションのシーケンスを誤って考慮し、このテストの失敗が発生します。</p><p>すべての適切なバグ修正と同様に、実際の修正は約<a href="https://github.com/apache/lucene/pull/13627/files">10 行のコード</a>です。しかし、実際に理解するまでに 2 人のエンジニアが数日かかりました。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt71d78f22ce6ec215/6a1706b61949f7bcd0e7a94a/7915e5ba2feba0fb8e846da0af11bfdca470c467-1600x622.jpg" alt="" /><h2>すべてのヒーローがマントを着ているわけではない</h2><p>はい、決まり文句ですが、それは真実です。</p><p></p><p>並行プログラムのデバッグは非常に重要です。これらの扱いにくい同時実行バグをデバッグして解決するには、膨大な時間がかかります。Rust のような新しい言語には、このような競合状態を防ぐためのメカニズムが組み込まれていますが、世の中のソフトウェアの大部分はすでに作成されており、しかも<a href="https://www.rust-lang.org/">Rust</a>以外の言語で書かれています。Java は、何年も経った今でも、最も使用されている言語の 1 つです。JVM ベースの言語でのデバッグを改善することで、ソフトウェア エンジニアリングの世界がより良くなります。また、一部の人々がコードは大規模言語モデルによって記述されると考えていることを考えると、エンジニアとしての私たちの仕事は、最終的には自分自身の悪いコードだけでなく、悪い LLM コードをデバッグすることだけになるかもしれません。しかし、ソフトウェア エンジニアリングの将来がどうであろうと、並行プログラムのデバッグはソフトウェアの保守と構築にとって重要なままです。</p><p></p><p>これをさらに素晴らしいものにしてくれた PASTA ラボの Ao Li 氏と同僚の皆さんに感謝します。</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/concurrency-bugs-lucene-debugging</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/concurrency-bugs-lucene-debugging</guid>
    <category><![CDATA[Lucene]]></category>
    <dc:creator><![CDATA[Benjamin Trent,Ao Li]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf9fcbf843affc566/6a1706b8964ceaea3208bab9/7884e35f40c15fe349379ef7ae4648b21708962f-1070x712.jpg" length="0" type="image/jpeg"/>
    <pubDate>Fri, 07 Feb 2025 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>