Ruby-反復時にマルチスレッド(生産者/消費者モデル)を使用した場合の予期しない結果

カートW

注:DNS名を解決するためにスレッドを使用することを選択していますが、同じ動作がどのタイプの同様の操作でも再現される可能性があります。


(以前は機能していた)コードを標準のシングルスレッド実行からマルチスレッドに移動しようとすると、予期しない結果が発生します。具体的には、私のコードはハッシュの配列を反復処理し、配列内の各ハッシュにキーと値のペアを追加します。

私が抱えている問題dns_cname.mapは、新しいキーと値のペアが作成されているループに起因しているようです。"external_dns_entry"正しい値(つまり、result.name.to_sDNSによって解決された名前を含む)を持つキーの代わりに、代わりに他の多くのサーバーの1つの名前を取得していますurl_nameserver_mapping

スレッドが利用可能になり、ハッシュが順不同に更新されると、DNS解決が行われているように感じますが、このような問題の追跡を開始する方法すらわかりません。

問題のある結果:server1に対して実行されたDNS解決はサーバー17にマッピングされています。同様に、サーバー17はサーバー99などにマッピングされています。残りのハッシュはそのままです。

どんな助けでも大歓迎です。よろしくお願いします!

マルチスレッドが有効になっていない場合の私のコード次のとおりです(正しく機能します)。

url_nameserver_mapping = { "server1" => "dallasdns.dns.com",
                           "server2" => "portlanddns.dns.com",
                           "server3" => "losangelesdns.dns.com" }


# Parse the JSON string response from the API into a valid Ruby Hash
# The net/http GET request is not shown here for brevity but it was stored in 'response'
unsorted_urls = JSON.parse(response.body)

# Sort (not sure this is relevant)
# I left it since my data is being populated to the Hash incorrectly (w/ threading enabled)
url_properties = unsorted_urls['hostnames']['items'].sort_by { |k| k["server"]}

url_nameserver_mapping.each do |server,location|

      dns = Resolv::DNS.new(:nameserver => ['8.8.8.8'])
      dns_cname = dns.getresources(server, Resolv::DNS::Resource::IN::CNAME)

      dns_cname.map do |result|
         # Create a new key/value for each Hash in url_properties Array
         # Occurs if the server compared matches the value of url['server'] key
         url_properties.each do |url|
           url["external_dns_entry"] = result.name.to_s if url['server'] == server
         end
      end

end

https://blog.engineyard.cm/2013/ruby-concurrencyのガイドに従って、プロデューサー/コンシューマースレッドモデルを実装しました。

マルチスレッドが有効になっている(機能していない)場合の適応コードは次のとおりです。

require 'thread'
require 'monitor'

thread_count = 8
threads = Array.new(thread_count)
producer_queue = SizedQueue.new(thread_count)
threads.extend(MonitorMixin)
threads_available = threads.new_cond
sysexit = false

url_nameserver_mapping = { "server1" => "dallasdns.dns.com",
                           "server2" => "portlanddns.dns.com",
                           "server3" => "losangelesdns.dns.com" }


unsorted_urls = JSON.parse(response.body)

url_properties = unsorted_urls['hostnames']['items'].sort_by { |k| k["server"]}

####################
##### Consumer #####
####################

consumer_thread = Thread.new do

  loop do

    break if sysexit && producer_queue.length == 0
    found_index = nil

    threads.synchronize do
      threads_available.wait_while do
        threads.select { |thread| thread.nil? ||
                                  thread.status == false ||
                                  thread["finished"].nil? == false}.length == 0
      end
      # Get the index of the available thread
      found_index = threads.rindex { |thread| thread.nil? ||
                                              thread.status == false ||
                                              thread["finished"].nil? == false }
    end

    @domain = producer_queue.pop

      threads[found_index] = Thread.new(@domain) do

        dns = Resolv::DNS.new(:nameserver => ['8.8.8.8'])
        dns_cname = dns.getresources(@domain, Resolv::DNS::Resource::IN::CNAME)

        dns_cname.map do |result|
           url_properties.each do |url|
             url["external_dns_entry"] = result.name.to_s if url['server'] == @domain
           end
        end

        Thread.current["finished"] = true

        # Notify the consumer that another batch of work has been completed
        threads.synchronize { threads_available.signal }
      end
  end
end

####################
##### Producer #####
####################

producer_thread = Thread.new do

  url_nameserver_mapping.each do |server,location|

    producer_queue << server

    threads.synchronize do
      threads_available.signal
    end
  end
  sysexit = true
end

# Join on both the producer and consumer threads so the main thread doesn't exit
producer_thread.join
consumer_thread.join

# Join on the child processes to allow them to finish
threads.each do |thread|
  thread.join unless thread.nil?
end
フレデリック・チャン

@domainはすべてのスレッドで共有されます-この共有が問題の根本です。キューから次の作業単位をポップして更新すると、すべてのスレッドでその変更が確認されます。あなたはすることによってこの問題を回避することができます

Thread.new(producer_queue.pop) do |domain|
   #domain isn't shared with anyone (as long as there
   #is no local variable called domain in the enclosing scope
end

あなたの質問に正接しますが、これは本当に過剰に設計されたアプローチが好きだったようです。多数のコンシューマースレッドを事前にスピンアップして、作業キューから直接読み取らせる方がはるかに簡単です。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

マルチスレッドの生産者/消費者による実行モードとdeburgモードでの異なる結果

分類Dev

生産者/消費者モデルを使用したファイルの処理

分類Dev

Java(同期)を使用する生産者/消費者モデルですが、常に同じスレッドを実行します

分類Dev

スレッドとEventWaitHandleを使用した生産者/消費者パターン

分類Dev

DeliveryBoy(kafka-ruby)によって書かれたメッセージを消費しないレースカー

分類Dev

pthreadを使用した競合状態の消費者-生産者

分類Dev

Ruby FileUtilsmkdir_pモード-予期しない結果

分類Dev

Rubyマルチスレッドの奇妙な振る舞い

分類Dev

Dockerビルドキット `RUN mount = type = cache`予期しない動作キャッシュrubyバンドルのインストール結果

分類Dev

マルチスレッドの場合の予期しない結果

分類Dev

ベンチマーク時にミューテックスなしでマルチスレッドが遅くなる(ruby 2.0、rails Rails 4.2.7.1)

分類Dev

Rubyでリアルタイムに作成された新しいスレッドから結果を非同期的に収集する方法

分類Dev

luaコルーチンによって実装された生産者/消費者モデルが期待どおりに機能しないのはなぜですか?

分類Dev

予期しない値を出力するRubyスイッチ

分類Dev

pthreadとセマフォを使用した生産者/消費者問題の実装に支援が必要

分類Dev

Rubyのインストールに使用されたプログラムがわからない場合にRubyバージョンをアップグレードするにはどうすればよいですか?

分類Dev

Ruby:同時/マルチスレッドタスクのCPU負荷の低下?

分類Dev

Javaの生産者/消費者問題でアトミック整数を使用した奇妙な出力

分類Dev

複数の生産者の消費者に、これ以上結果がないことを伝えます

分類Dev

Rubyの `next`メソッドがSyntaxErrorを発生させるのに、` next! `または` self.next`がStringクラスにモンキーパッチを適用しているときに発生しないのはなぜですか?

分類Dev

Rubyスレッドの結果をパラメーターとしてメソッドに渡します

分類Dev

生産者/消費者セマフォの値が正しくない

分類Dev

生産者-消費者の例が機能しない

分類Dev

Ruby on Rails-CoffeeScriptのActionView :: Template :: Error(SyntaxErrorが予期しない場合)

分類Dev

Ruby onRailsでインクルードまたは結合を使用して他のテーブルの結果を取得する方法

分類Dev

Rubyは、コレクションを反復処理してハッシュキーが存在しない場合は作成する方法、またはキーが存在する場合は値に追加する方法

分類Dev

(Lua)生産者/消費者のLuaコルーチン実験で、期待される結果が得られないのはなぜですか?

分類Dev

何も存在しない場合にプレースホルダーを表示する方法(Ruby on Rails)

分類Dev

画像が存在しない場合にデフォルトのユーザー画像を表示するには(Ruby on Rails)

Related 関連記事

  1. 1

    マルチスレッドの生産者/消費者による実行モードとdeburgモードでの異なる結果

  2. 2

    生産者/消費者モデルを使用したファイルの処理

  3. 3

    Java(同期)を使用する生産者/消費者モデルですが、常に同じスレッドを実行します

  4. 4

    スレッドとEventWaitHandleを使用した生産者/消費者パターン

  5. 5

    DeliveryBoy(kafka-ruby)によって書かれたメッセージを消費しないレースカー

  6. 6

    pthreadを使用した競合状態の消費者-生産者

  7. 7

    Ruby FileUtilsmkdir_pモード-予期しない結果

  8. 8

    Rubyマルチスレッドの奇妙な振る舞い

  9. 9

    Dockerビルドキット `RUN mount = type = cache`予期しない動作キャッシュrubyバンドルのインストール結果

  10. 10

    マルチスレッドの場合の予期しない結果

  11. 11

    ベンチマーク時にミューテックスなしでマルチスレッドが遅くなる(ruby 2.0、rails Rails 4.2.7.1)

  12. 12

    Rubyでリアルタイムに作成された新しいスレッドから結果を非同期的に収集する方法

  13. 13

    luaコルーチンによって実装された生産者/消費者モデルが期待どおりに機能しないのはなぜですか?

  14. 14

    予期しない値を出力するRubyスイッチ

  15. 15

    pthreadとセマフォを使用した生産者/消費者問題の実装に支援が必要

  16. 16

    Rubyのインストールに使用されたプログラムがわからない場合にRubyバージョンをアップグレードするにはどうすればよいですか?

  17. 17

    Ruby:同時/マルチスレッドタスクのCPU負荷の低下?

  18. 18

    Javaの生産者/消費者問題でアトミック整数を使用した奇妙な出力

  19. 19

    複数の生産者の消費者に、これ以上結果がないことを伝えます

  20. 20

    Rubyの `next`メソッドがSyntaxErrorを発生させるのに、` next! `または` self.next`がStringクラスにモンキーパッチを適用しているときに発生しないのはなぜですか?

  21. 21

    Rubyスレッドの結果をパラメーターとしてメソッドに渡します

  22. 22

    生産者/消費者セマフォの値が正しくない

  23. 23

    生産者-消費者の例が機能しない

  24. 24

    Ruby on Rails-CoffeeScriptのActionView :: Template :: Error(SyntaxErrorが予期しない場合)

  25. 25

    Ruby onRailsでインクルードまたは結合を使用して他のテーブルの結果を取得する方法

  26. 26

    Rubyは、コレクションを反復処理してハッシュキーが存在しない場合は作成する方法、またはキーが存在する場合は値に追加する方法

  27. 27

    (Lua)生産者/消費者のLuaコルーチン実験で、期待される結果が得られないのはなぜですか?

  28. 28

    何も存在しない場合にプレースホルダーを表示する方法(Ruby on Rails)

  29. 29

    画像が存在しない場合にデフォルトのユーザー画像を表示するには(Ruby on Rails)

ホットタグ

アーカイブ