ex6 — スレッドとネットワーク通信の暗号化¶
小テスト¶
小テストは 4 講時の講義パートのあとに行います。問題は前回の aiJudge 課題の内容に沿っています。受験できるのは 1-608 の教室だけで、オンラインでは受験できません。
16:30〜16:45 の 15 分間で、aiJudge の次の課題に取り組んでください。
- statusCode.py
演習課題¶
演習課題 1. aiJudge の ex6 に取り組む¶
aiJudge の ex6 にある次の課題すべてで、満点を取ってください。
- httpThreadServer.py
- httpThreadServer3.py
スレッドの使い方は thread.py を参考にしてください(読み方はこのページのメモ)。 aiJudge は、提出されたサーバに 1 つ目のクライアントを接続したまま待たせ、その間に 2 つ目のクライアントから要求を送ります。 aiJudge は、2 つ目の要求に応答が返ってくるか、つまりサーバが要求を並列に処理できているかを採点します。
メモ:thread.py を読む¶
thread.py は、同じ関数を「順に呼び出す」場合と「スレッドで動かす」場合を比べるサンプルです。
3 つの関数¶
f1()はf1 0〜f1 4を 0.5 秒おきに表示します(Repeat = 5)。f2()は 0.4 秒おきですfx(n)は、引数で受け取ったn秒おきに表示します。fx(1)は 1 秒おき、fx(2)は 2 秒おきですsleep()で待っている間、プログラムは何もしていません。サーバがaccept()やrecv()で相手を待っている状態と同じです
前半: 順に呼び出す¶
1 つの関数が終わってから、次の関数が始まります。出力は f1 の 5 行、f2 の 5 行、… の順に並び、毎回同じです。
かかる時間は、それぞれの待ち時間の合計で、約 19.5 秒(2.5 + 2 + 5 + 10)です。
後半: スレッドで動かす¶
thread1 = threading.Thread(target=f1)
thread1x = threading.Thread(target=fx, args=(1,))
...
thread1.start()
...
print("### end threads???")
thread1.join()
...
print("### end threads!!!")
threading.Thread(target=関数, args=引数のタプル)で、関数を別のスレッドで動かす準備をしますtarget=f1のように、関数そのものを渡します。target=f1()と書くと、その場でf1を呼び出してしまい(スレッドではなく、普通の呼び出しになる)、スレッドには戻り値のNoneが渡りますargs=(1,)のカンマは必要です。(1)はただの整数 1 で、タプルになりません。args=(1)と書くと、スレッドの中でTypeError: ... argument after * must be an iterable, not intが発生します
start()でスレッドが動き始めます。呼び出した側は終わりを待たずに、すぐ次の行へ進みます- そのため、
### end threads???は、スレッドがまだ動いている途中で表示されます。???は「本当に終わった?」という意味です
- そのため、
join()は、そのスレッドが終わるまで待ちます。4 つすべてをjoin()してから表示するので、### end threads!!!は本当に全部が終わった後に表示されます
4 つのスレッドは同時に待つので、かかる時間は一番長い fx(2) の約 10 秒です。前半の約 19.5 秒より短くなります。
計算が速くなったのではなく、待ち時間を重ねたことで短くなっています(第 6 回のスライド「スレッドで気をつけること」)。
実行結果の読み方¶
後半の出力は、たとえば次のようになります。順番は実行のたびに変わります。
### start threads
f1f2fx fx0
2 0
1 00
### end threads???
f2 1
f1 1
f2 2
fx 1 1
...
fx 2 4
### end threads!!!
f1とf2とfxの行が混ざって表示されます。どのスレッドが先に動くかは OS が決めるので、決まった順番はありませんf1f2fx fx0のように、1 行の中で文字が混ざることがあります。print("f1", i)は、f1・区切りの空白・0・改行を別々に書き出すので、その間に別のスレッドのprint()が割り込むためです- 複数のスレッドが同じもの(ここでは画面)を同時に使うと、こうした混ざりが起きます
試してみよう¶
- 何回か実行して、後半の順番が毎回変わることを確かめる
join()の 4 行を消して実行する。### end threads!!!が、スレッドの途中ですぐに表示されることを確かめる(プログラム自体は、すべてのスレッドが終わるまで終了しません)-
httpThreadServer.pyでは、f1の代わりに 1 つの接続を処理する関数を、argsに(conn, addr)を渡してスレッドで動かします