インタビューにおけるPython開発者の一般的な落とし穴





みなさん、こんにちは。今日は、多くの求職者が直面している困難や誤解についてお話ししたいと思います。私たちの会社は活発に成長しており、私はしばしばインタビューを行ったり参加したりしています。その結果、多くの候補者を困難な立場に置くいくつかの問題を特定しました。それらを一緒に見てみましょう。Python固有の質問について説明しますが、全体として、この記事はあらゆる仕事のインタビューに役立ちます。経験豊富な開発者の場合、ここでは真実は明らかになりませんが、旅を始めたばかりの人にとっては、今後数日間のトピックを決定する方が簡単です。



Linuxのプロセスとスレッドの違い



さて、あなたは知っています、そのような典型的で一般的に単純な質問は、詳細や微妙なことを掘り下げることなく、純粋に理解するためのものです。もちろん、ほとんどの申請者は、スレッドは軽量であり、コンテキストはスレッド間でより速く切り替わり、一般的にはプロセス内に存在すると言うでしょう。そして、Linuxについて話していないときは、これはすべて正しくて素晴らしいことです。 Linuxカーネルでは、スレッドは通常のプロセスと同じ方法で実装されます。スレッドは、一部のリソースを他のプロセスと共有するプロセスです。



Linuxでプロセスを作成するために使用できる2つのシステム呼び出しがあります。



  • clone()



    . . , . ( , , ).
  • fork()



    . ( ), clone()



    .


私は次のことを指摘しfork()



ます。プロセスを作成しても、親プロセスのメモリのコピーをすぐに取得することはありません。プロセスは、単一のメモリ内インスタンスで実行されます。したがって、合計でメモリオーバーフローが発生した場合でも、すべてが引き続き機能します。カーネルは、親プロセスのメモリページ記述子を読み取り専用としてマークし、(子または親プロセスによって)それらに書き込もうとすると、例外が発生して処理され、完全なコピーが作成されます。このメカニズムは、コピーオンライトと呼ばれます。



LinuxはLinuxデバイスに関する素晴らしい本だと思います。システムプログラミング "RobertLoveによる。



イベントループの問題



PythonまたはGoの非同期サービスとワーカーは、当社の至る所にあります。したがって、非同期性とイベントループがどのように機能するかについて共通の理解を持つことが重要であると考えています。多くの候補者は、非同期アプローチの利点に関する質問に答えるのにすでにかなり優れており、特定のイベントがオペレーティングシステムから発生したかどうかを理解できる一種の無限ループとしてイベントループを正しく表します(たとえば、ソケットへのデータの書き込み)。しかし、接着剤が欠けています。プログラムはどのようにしてオペレーティングシステムからこの情報を取得するのでしょうか。



もちろん、覚えておくべき最も簡単なことはSelect



..。その助けを借りて、監視する予定のファイル記述子のリストが作成されます。クライアントコードは、渡されたすべてのハンドルでイベントをチェックする必要があり(その数は1024に制限されています)、遅くて不便です。



についての答えはSelect



十分すぎるほどですが、Poll



またはについて覚えていてEpoll



、それらが解決する問題について話す場合、これはあなたの答えに大きなプラスになります。不必要な心配をしないために、Cコードや詳細な仕様は求められず、何が起こっているのかについての基本的な理解についてのみ話します。違いについて読んでくださいSelect



Poll



そしてこの記事でEpoll



できます



また、DavidBeasleyによるPythonの非同期のトピックを確認することをお勧めします



GILは保護しますが、あなたは保護しません



もう1つのよくある誤解は、GILは開発者を同時データアクセスの問題から保護するように設計されているというものです。しかし、そうではありません。もちろん、GILは、プログラムをスレッド(プロセスではなく)と並列化することを防ぎます。簡単に言うと、GILは、Pythonを呼び出す前に取得する必要のあるロックです(それほど重要ではありません。Pythonコードが実行されるか、Python C APIが呼び出されます)。したがって、GILは内部構造を一貫性のない状態から保護しますが、他の言語と同様に、同期プリミティブを使用する必要があります。



また、GILはGCが正しく機能するためにのみ必要であるとも言われています。彼女にとって、彼はもちろん必要ですが、これで終わりではありません。



実行の観点から、最も単純な関数でさえいくつかのステップに分解されます。



import dis

def sum_2(a, b):
    return a + b

dis.dis(sum_2)


4           0 LOAD_FAST                0 (a)
             2 LOAD_FAST                1 (b)
             4 BINARY_ADD
             6 RETURN_VALUE

      
      





プロセッサの観点からは、これらの各操作はアトミックではありません。 Pythonは、バイトコードの1行ごとに多くのプロセッサ命令を実行します。この場合、他のスレッドがスタックの状態を変更したり、他のメモリを変更したりすることを許可しないでください。これにより、セグメンテーション障害または不正な動作が発生します。したがって、インタプリタは各バイトコード命令のグローバルロックを要求します。ただし、コンテキストは個々の命令間で変更できます。ここでは、GILによって保存されることはありません。バイトコードとその操作方法の詳細については、ドキュメントを参照してください



GILセキュリティのトピックについては、簡単な例を参照してください。



import threading

a = 0
def x():
    global a
    for i in range(100000):
        a += 1

threads = []

for j in range(10):
    thread = threading.Thread(target=x)
    threads.append(thread)
    thread.start()

for thread in threads:
    thread.join()

assert a == 1000000

      
      





私のマシンでは、エラーは安定してクラッシュします。突然機能しない場合は、数回実行するか、スレッドを追加してください。スレッドの数が少ないと、フローティングの問題が発生します(エラーが表示され、表示されません)。つまり、誤ったデータに加えて、そのような状況には、その浮動性という形で問題があります。これにより、次の問題である同期プリミティブも発生します。



繰り返しになりますが、私はDavidBeasleyに言及せざるを得ません



同期プリミティブ



一般に、同期プリミティブはPythonにとって最良の質問ではありませんが、問題の一般的な理解と、この方向にどれだけ深く掘り下げたかを示しています。マルチスレッドのトピックは、少なくとも私たちにとっては、ボーナスとして求められ、プラスになるだけです(あなたが答えた場合)。しかし、まだ遭遇していなくても大丈夫です。この質問は特定の言語に結び付けられていないと言えます。



私が上で書いたように、多くの初心者のpythonistは、GILの奇跡的な力を望んでいるので、同期プリミティブのトピックを調べません。しかし、無駄に、バックグラウンドの操作やタスクを実行するときに便利です。同期プリミティブのトピックは大きく、よく理解されています。特に、Wesley J.Chunによる「CorePythonApplicationsProgramming」という本でそれについて読むことをお勧めします。



また、GILがスレッドの操作に役立たなかった例をすでに見てきたので、そのような問題から保護する方法の最も簡単な例を検討します。



import threading
lock = threading.Lock()

a = 0
def x():
    global a
    lock.acquire()
    try:
        for i in range(100000):
            a += 1
    finally:
        lock.release()

threads = []

for j in range(10):
    thread = threading.Thread(target=x)
    threads.append(thread)
    thread.start()

for thread in threads:
    thread.join()

assert a == 1000000

      
      





頭全体で再試行



インフラストラクチャが常に安定して機能するという事実に頼ることはできません。インタビューでは、他の人と対話する(たとえば、HTTPを介して)単純なマイクロサービスを設計するように依頼することがよくあります。サービスの安定性の問題により、候補者が混乱することがあります。HTTPを介した再試行を提案する際に、候補者が見落としているいくつかの問題を指摘したいと思います。



最初の問題:サービスが長時間機能しない可能性があります。リアルタイムで繰り返されるリクエストは無意味になります。



大まかに実行すると、負荷がかかった状態で速度が低下し始めたサービスを終了できます。彼が必要としているのは負荷の増加ですが、これは繰り返しの要求によって大幅に増加する可能性があります。サービスが正常に機能し始めた後、状態を保存してディスパッチを実装する方法について説明することは、常に興味深いことです。



または、プロトコルをHTTPから配信が保証されたもの(AMQPなど)に変更してみることもできます。



サービスメッシュは、再試行タスクを引き継ぐこともできます。あなたはこの記事でもっと読むことができます



全体として、私が言ったように、ここに驚きはありませんが、この記事は、どのトピックを取り上げるべきかを理解するのに役立ちます。インタビューだけでなく、進行中のプロセスの本質をより深く理解するためにも。



All Articles