4

総括:

スレッドを使用して Web から情報をスクレイピングするアプリケーションの簡単な例を作成しようとしています。これ専用のモジュール (scrapy など) があることは知っていますが、スレッドがどのように機能するかを学び、理解し、落とし穴を理解するために、もっとやりたいと思いました。さらに、さまざまなチュートリアル (IBM チュートリアルなど)、SO に関する質問、さらにはPython Cookbook, 3rd Ed. のいくつかのレシピを見てきました。それを行う方法を説明していますが、スレッド/キューを使用しているときにまだどこかでハングアップしています。

まず、stackoverflow (およびクックブック) で、 をサブクラス化するのは無駄だと読んだthreading.Threadので、 を使用してそれをやろうとしましたThread(target=..., args=(...))。ほとんどのチュートリアルでは、(古い?) サブクラス化方法を使用しているように見えますが、この新しい(?) 方法に進むと混乱する可能性があります。

2 つ目は、Python クックブックで、値を作業キューに配置する例を示し_sentinelています。これは、メソッドが監視し、発見した場合に中断します。ここが困っているところだと思います。

最後に、私はあらゆる種類のやり過ぎに取り組んでいるに違いないと確信しているので、物事を過度に複雑にしている場所に関するヒントや指針をいただければ幸いです。ご提案いただきありがとうございます。


特定のコーディングの問題と試み:

(会社名、URL) タプルの work_queue があります。私の方法は、株式ティッカー名の URL を解析し、タプル (ティッカー名、会社名) を出力キューに送信することです。すべての値が消費されたときに、センチネルを使用してメソッドから抜け出そうとしています:

def grab_ticker_name(input_q, output_q, _sentinel):
    '''Function to be threaded later: grabs company ticker from url and sends it to an output queue.'''

  while True:
      item = input_q.get()
      if item is _sentinel:
          print("We encountered the sentinel!!")
          input_q.put(_sentinel) # See page 492 of Python Cookbook, 3rd Ed.
          break
      else:
          company_name, company_url = item
          with urlopen(company_url) as f:
              newsoup = BeautifulSoup(f)
              if len(newsoup.select('.inlink_chart > a')) > 0:
                  ticker_name = newsoup.select('.inlink_chart > a')[0].string
                  output_q.put((ticker_name, company_name))
                  print("grab_ticker_name grabbed the following: {ticker_name}, {company_name}".format_map(vars()))
          input_q.task_done()

キューにデータを入力し、次のようにスレッドを構築printしています (何が起こっているのかを確認するのに役立つステートメントを使用しています)。

def main():
    work_queue = queue.Queue()
    out_queue = queue.Queue()
    _sentinel = object() # This recommendation comes from the *Python Cookbook*
    stock_list = StockBuilder()
    print("Populating the work_queue now")
    for item in stock_list.yield_url():
        work_queue.put(item)
    work_queue.put(_sentinel)

    t1 = threading.Thread(target=grab_ticker_name, args=(work_queue, out_queue, _sentinel))
    t2 = threading.Thread(target=grab_ticker_name, args=(work_queue, out_queue, _sentinel))
    print("Now we're going to start our threads!")
    t1.start() ; t2.start()
    print("Now we're going to attempt to join our work queue.")
    work_queue.join()

それは機能しているように見え、値の行ごとに行を返しますが、キャンセルする必要があるまで無限にループしているように見えます (CTRL + C):

...
grab_ticker_name grabbed the following: MRK, Merk
grab_ticker_name grabbed the following: HUM, Humana
We encountered the sentinel!!
grab_ticker_name grabbed the following: WLP, WellPoint
We encountered the sentinel!!
^CTraceback (most recent call last).
...

質問break:関数が main() に戻るように式が作成されないのはなぜですか?

out_queue最後に、からすべてのデータを取得して、別のデータ構造 (リスト、辞書など) に配置できるようにしたいと考えています。

質問 2:これにはロック付きのリストを使用できることはわかっていますが、スレッドが可変オブジェクトを変更するためのより簡単な方法はキューであると読んだと思っていたので、ここでも混乱していますか?

質問 2a : out_queue を使用すると仮定すると、データが取り込まれたら、そこout_queueからすべての値を単純に取得する簡単な方法はありますか? 私はおそらく別のものをアフターに入れ_sentinelout_queuework_queue.join()のループを実行して、そうでない場合whileは各アイテムで作業すると思いましたか? これはこれを行う単純な方法ですか?out_queue_sentinel

読んでくれてありがとう。

4

1 に答える 1

3

問題は、あなたが に参加しようとしていることですがwork_queue、 がwork_queue空ではないことです。まだセンチネルが含まれています。代わりにこれを試してください:

t1.join()
t2.join()
于 2013-08-04T22:58:57.650 に答える