同じ値を2回返さないことが保証されている関数[終了]


23

これは私が就職の面接で尋ねられた質問であり、彼らが探していた答えがわからないので、私はここの誰かがいくつかのアイデアを持っていることを望んでいます。目標は、同じ値を2回返さないことが保証されている関数を作成することです。この機能は、複数のマシンから同時にアクセスされると仮定します。

私のアイデアは、各マシンに一意のIDを割り当て、その値を一意の値ジェネレーター関数に渡すことでした。

var i = 0;
function uniq(process_id, machine_id) {
   return (i += 1).toString() + machine_id + "-" + process_id;
}

これにより、2つ以上のプロセスがの同じ値を読み取った場合でもi、各戻り値にプロセスIDとマシンIDの一意の組み合わせがタグ付けされるため、競合状態からのフォールアウトが回避されます。ただし、別のマシンをオンラインにするにはIDを割り当てる必要があるため、私のインタビュアーはこの回答を好みませんでした。

だから誰もこれを解決する別の方法を考えることができますか?それは一意のIDを持つように各マシンを構成することを必要としませんか?この質問が再び出てくる場合に備えて、回答が欲しいです。ありがとう。


31
厳密な意味で保証されていますか?つまり、Guidsでさえ、ある時点で自分自身を繰り返すようになります。私たちはもう住んでいるが、保証...ところで、プロセスIDがあるない場合もユニークであることにはほど遠いです
JensG 14年

7
@CodesInChaos-Macアドレスを変更することは一部のオペレーティングシステムでは簡単であるため、これはかなり恐ろしい仮定です。
テラスティン14年

7
「この機能は複数のマシンから同時にアクセスされることを想定しています」-正直なところ、これは「コードが各マシンで個別に実行され、マシン間で通信が行われない」、または「中央マシン/中央データベースがあり、機能がネットワークを介して利用可能な他のマシンに提供されます。」最初にこれを明確にする必要があります。
Doc Brown 14年

28
トリックの質問でしたか?例えば、無限ループを含む関数は二度同じ値を返すことはありません...
ブレンダン・

8
おそらく彼らは、怪しげな要件についての質問をするプログラマを探しているのではなく、仮定を作り、それを実行していた:)
theMayer

回答:


60

派手なことはせず、通信エンドポイント(WCF、Webサービスなど)の背後に単純な(スレッドセーフな)カウンターを投げるだけです。

   long x = long.MinValue;
   public long ID(){
       return Interlocked.Increment(ref x);
   }

はい、最終的にオーバーフローします。はい、再起動は処理しません。はい、ランダムではありません。はい、誰かがこれを複数のサーバーで実行できます。

これは、実際の要件を満たす最も単純なものです。次に、それらをそれらの問題のフォローアップにします(制限を確実に理解するために、2 ^ 64を超えるIDが必要本当に考えますか)。その後、どのトレードオフが大丈夫かを尋ねることができます。再起動に耐える必要がありますか?ハードドライブの故障はどうですか?核戦争はどうですか?ランダムにする必要がありますか?どのくらいランダムですか?


7
インタビュアーは質問をして直接回答を得ることがないため、これは良い答えです。彼らは、あなたがあなたの決定を正当化できる答えをあなたに与えて欲しいのです。ドメインを理解していれば、正当化できればほぼすべての回答が適切です。

7
コードが異なるマシンで実行される場合(明らかに異なるプロセスで実行される場合)、これはどのように機能しますか?各プロセスにはの異なるコピーがありxます。そして、あなたが念頭に置いているインターロック機構の種類についての説明がなければ、この答えはかなり曖昧だと思います。
Doc Brown 14年

7
「複数のマシンが同時にアクセスする」@DocBrownは、複数のマシンが単一のサーバー上の単一の機能にアクセスすることを暗示しているようです。それ以外の場合は、「複数のマシンが同時にこの関数のコピーを実行します」言葉で表現されなければならない
ファルコ

3
@LightnessRacesinOrbit:これは、C#、およびSystem.Threading.Interlockedアトミックな増分を提供するクラスを意味するものだと思います。ただし、これは何らかの疑似コードとして読み取ることもできます。
ドックブラウン14年

3
もし私が質問する人なら、私はこの提案に非常に不満を感じるでしょう。要件が何であるかさえ知らずに何かを実装し始めることは大きな危険です。私はあなたが尋ねることを期待しています。
JensG 14年

25

その質問があり、再起動と異なるマシン間で一意でなければならないことを明確にした場合、新しいGUIDを作成するための標準メカニズムを呼び出す関数を提供します使用されている言語。


v4 GUIDの問題は、それらが一意である可能性が非常に高いことであり、一意であるとは限りません。実際には大きな問題ではありませんが、インタビュアーが文字どおりに要件を満たせば要件を満たしません。
CodesInChaos 14年

特に、標準のGUIDメカニズムがインタビュアーの要件を満たしていない場合は、インタビュアーとGUIDの通常のユーザーとの間の要件の違いを理解します。この種の質問をする賢明なインタビュアー(「通常の要件とは少し異なる可能性のある一般的に知られている標準的なこと」)最初から何かを発明しているGUIDおよび候補者向け。
スティーブジェソップ14年

これはおそらく、柔軟な要件を想定した最も単純な答えです。
theMayer 14年

9
これは基本的にはGUIDが解決する問題だからです。複製のGUIDを生成することは、その形式に関係なく、地球上で最も難しい宝くじです。どうやら多くの人々は、衝突の指数関数的な可能性について感覚を持っていません。
usr 14年

3
ああ、そのような質問に対して「標準機能を使用する」という回答を提供する場合は、「標準機能はどのように実装されているのか」という追加の質問を期待してください。「わからないが、何かを発明しようとするのではなく、間違いなく調べたい」と答える方が良いかもしれません。あなたがしたいこと、これまでやる何も最初にそれを研究することなく、重要なの;-)
スティーブ・ジェソップ

22

インタビュアーは、メソッドは並行ではなく並行して呼び出されると述べた。できる限り小数点以下の桁まで日付/時刻を返すだけです。

誰もがこれを過剰に考えているのはなぜですか?有限性が費やされる前に、あなたは長い間死んでいて、衝突の可能性がありません。

同じ時間を返すことが心配な場合は、測定可能な最小時間の遅延を追加します。

夏時間のために時計を戻すことを心配している場合(1回の2回の経験)、2回目に経験する時間に定数を追加します。


12
または、リクエスタのタイムゾーンに関係なく、UTC時間を返します。UTCはローカライズされていないため、DSTの変更による影響を受けません。
マウロ14年

1
System.currentTimeNanos():-)
ファルコ14年

1
人間が読める形式で日付と時刻を返す場合を除き、値にはタイムゾーン情報が含まれていてはなりません。
モニカとの軽さのレース14

12
頻繁に/同時に十分に呼び出された場合でも、最小の時間で衝突が発生します。また、クロック同期ドリフト、悪意のあるクロック操作、および注意しないと夏時間による衝突が発生します。
テラスティン14年

1
少なくとも非常に創造的です。時々調整されるクロックに依存することは、まだそれほど素晴らしいアイデアではありません。オフセットは衝突からあなたを救いません。
JensG 14年

15

まず、インタビュアーに2つの質問をします。


質問1。

インタビュアーが1つまたは複数の「中央マシン」を使用して、いくつかの一意の番号または一意の番号のブロックを割り当てることを期待するかどうか。


質問2。

インタビュアーが衝突検出のメカニズムを期待しているのか、それとも明示的に検出せずに衝突のごくわずかな可能性の計算されたリスクを受け入れるのか。

多層防御アプローチもあります。このアプローチでは、ユーザーIDの一部をランダム性に組み込みます(したがって、完全にランダムではありません)。したがって、同じユーザーが作成したコンテンツ内で同じユーザーが衝突する可能性は低くなります。


暗黙の質問3があります...

しかし、面接官に尋ねることは非常に失礼なので、尋ねることなく自分自身を測定しなければならないものです。

インタビュアーが確率、リスク、および暗号化システムと情報セキュリティシステムで採用されているいくつかの簡単なテクニックの知識を引き受けるかどうか。

最初の種類の知識は、あなたが受け入れない科学的概念を受け入れるように非科学的な人を説得しようとしていないことを保証します。

2番目の種類の知識は、単なる確率に加えて懸念に対処することを保証します。つまり、マシンまたはその仮想ホストを操作して2つのマシンに同じ値を強制的に生成させることにより、ランダム化スキームを意図的に破りたい「攻撃者」に対する防御方法です。


何で質問する。

その理由は、インタビュアーが何らかの形でそれを期待している場合、反対のアプローチで答えようとしてもインタビュアーが幸せになることは決してないからです。

より深い理由は、一部の人々が言うという考え1.0e-20、失敗する可能性を好まないということです。(ここでは、哲学的または宗教的な議論を巻き起こさないようにします。)


まず、乱数の「名前空間」が階層化され、特定の数のビットがランダム化の1つのソースに割り当てられ、他の数のビットが他の方法に割り当てられます。

中央集中型のアプローチは、第1レベルのビットを一意に割り当てる中央機関に依存しています。その後、他のマシンが残りのビットを埋めることができます。

いくつかの分散型アプローチがあります。

  • できるだけ良い乱数を生成し、計算によって正当化されないという事実上ゼロの可能性を受け入れます。
  • 決定論的なソースからランダムな値、たとえば増分値を生成する暗号化手段を使用します。

これが最良の答えだと思います。その他は、要件のないソリューションです。
ジャックエイドリー14年

3番目の質問に注目してください-能力は安全な仮定であるか、少なくとも無関係なものであると思われます。企業が有能なインタビュアーを提供しなかった場合、選択プロセスにより大きな欠陥がある可能性があります。もしそうなら、彼/彼女は質問に感謝します。
theMayer 14年

1
「真に保証された一意性が必要なのか、それとも衝突の非常に低い確率が必要なのか」という質問に答えることができないのはなぜですか。そして、「これはどれほど安全である必要がありますか?攻撃者がメカニズムを破壊しようとしていると想定する必要がありますか?どんな種類の攻撃が心配ですか?」これらの質問への回答は、質問者がこれらの問題を理解しているか、そして彼らが何を期待しているかを明確にする必要があります。
jpmc26 14年

12

したがって、これは実際のシナリオではなくインタビューの質問であることを念頭に置いて、正しいアプローチ(およびおそらくインタビュアーが探しているもの)は明確な質問をするか、「できない終了します」その理由は次のとおりです。

インタビュアーが求めること:

同じ値を2回返さないことが保証されている関数を作成します。この機能は、複数のマシンから同時にアクセスされると仮定します。

インタビュアーに必要なもの:

この候補者は要件を効果的に評価し、必要なときに追加の入力を求めていますか?

想定しないでください。

エンジニアが要件を(SOWまたは仕様またはその他の要件ドキュメントを介して)渡されると、一部は自明であり、その他は完全に不明確です。これは後者の完璧な例です。前の回答が示したように、要件を満たすことができないため、(a)質問の性質に関して、または(b)システムの性質に関していくつかの主要な仮定を行わずに、この要件に対応する方法はありません。書かれたまま(不可能)。

答えのほとんどは、一連の仮定を介して問題を解決しようとする試みです。ただそれをすぐに終わらせ、それが間違っている場合、顧客にそれを心配させることを特に推奨します。

これは本当に悪いアプローチです。顧客として、私が不明確な要件を与え、エンジニアが出て行って、機能しないソリューションを構築した場合、私は彼らが最初に私に尋ねることを気にせずに仕事に行ってお金を費やしたことに腹を立てます。そのような無頓着な意思決定は、チームワークの欠如、批判的に考えることができず、判断力が乏しいことを示しています。安全性が重要なシステムでの生命の損失を含む、あらゆる形の負の結果につながる可能性があります。

質問する理由

この演習のポイントは、あいまいな要件に合わせて構築するのに費用と時間がかかることです。OPの場合、不可能なタスクが与えられています。最初のアクションは、明確化を求めることです。何が必要ですか?どの程度の一意性が必要ですか?値が一意でない場合はどうなりますか?これらの質問に対する答えは、数週間の時間と数分間の違いかもしれません。現実の世界では、複雑なシステム(多くのソフトウェアシステムを含む)のコストの最大の要因の1つは、要件が不明確で理解が不十分です。これは、高価で時間を浪費するバグ、再設計、顧客とチームのフラストレーション、そしてプロジェクトが十分に大きい場合のメディア報道の恥ずかしさにつながります。

想定するとどうなりますか?

航空宇宙産業での私の経歴と、航空宇宙の故障の非常に目に見える性質のために、この領域から例を挙げて重要なポイントを説明したいと思います。失敗した2つの火星ミッション-火星気候オービターと火星ポーラーランダーを調べてみましょう。どちらのミッションも、ソフトウェアの問題が原因で失敗しました。これは、エンジニアが不明確でコミュニケーションが不十分な要件に一部起因して、エンジニアが無効な仮定を行ったためです。

火星気候オービター -このケースは、通常、NASAが英語をメートル単位に変換しようとしたときに起こることとして引用されています。しかし、それは実際に何が起こったのかを過度に単純化し、貧弱な表現です。確かに、変換の問題がありましたが、それは設計段階での不十分な通信要件と不適切な検証/検証スキームが原因でした。さらに、2人の異なるエンジニアが飛行軌跡データから明らかであるため問題に気付いたとき、彼らはそれが伝送エラーであると仮定したため、適切なレベルに問題を上げませんでした。ミッションオペレーションチームが問題を認識した場合、それを修正してミッションを保存するのに十分な時間がありました。この場合、それが何であるかが認識されない不可能な論理条件があり、費用のかかるミッションの失敗につながりました。

火星ポーラーランダー-この事例はあまり知られていませんが、火星気候オービターの故障に一時的に近いため、より恥ずかしいかもしれません。このミッションでは、ソフトウェアがロケットの火星表面への降下を制御しました。地上40メートルの地点で、着陸の準備として着陸機の脚が展開しました。また、脚にセンサーがあり、動きを検出して(衝撃を受けたときに信号を送る)、ソフトウェアにエンジンを停止するよう指示します。何が起こったのかに関するNASAの最良の推測(複数の可能性のある障害と不完全なデータがあるため)は、それらの展開による脚の不規則な振動が同時に、不適切に表面上の40mのシャットダウン機構を引き起こし、110ドルのクラッシュと破壊をもたらすことですM宇宙船。この可能性は開発中に提起され、しかし、決して対処されませんでした。最終的に、ソフトウェアチームは、このコードの実行方法について無効な仮定を立てました(そのような仮定の1つは、テストが反対を示しているにもかかわらず、スプリアス信号が短すぎて拾い上げられないということです)。事実。

追加の考慮事項

人へのインタビューと評価は難しい仕事です。インタビュアーが探求したいと思うかもしれない候補者のいくつかの側面がありますが、最も重要なものの1つは批判的に考える個人の能力です。批判的思考の定義が不十分であることなど、さまざまな理由で、批判的思考スキルを評価するのは非常に困難です。

工学のインストラクターとして、批判的に考える学生の能力を評価する私のお気に入りの方法の1つは、やや曖昧な質問をすることでした。より鋭い生徒は、質問の誤った前提を取り上げ、それを書き留め、前提が与えられれば答えるか、完全に答えることを拒否します。通常、次のような質問をします。

作業のスタックから図面を選択します。図面にはさまざまな異なる吹き出しが含まれていますが、水平面の最も重要なポイントであり、「完全にフラット」と表示されています。表面は幅5 "、長さ16"で、部品はアルミニウム製です。部品をどのように加工してこの機能を作成しますか?

(ちなみに、このような仕様が職場で頻繁に現れることにショックを受けるでしょう。)

生徒は、完璧な機能を作成することは不可能であると認識し、これを回答に記載することを期待しています。彼らがデザイナーに戻って部品を作る前に明確化を求めると彼らが言うならば、私は通常ボーナスポイントを授与します。学生が.001平面性またはその他の構成値を達成する方法を教えてくれると、ゼロポイントが与えられます。これは、生徒がより大きな全体像について考える必要があることを指摘するのに役立ちます。

ボトムライン

エンジニア(または同様の職業)にインタビューする場合、批判的に考え、彼の前に何が置かれているのかを質問できる人を探しています。「これは理にかなっていますか?」という質問をする人が欲しいです。。

完璧なものはないので、完全に平らな部品を要求するのは意味がありません。そのような保証をすることは不可能であるため、重複した値を決して返さない関数を要求することは意味がありません。プログラミングでは、「ガベージイン、ガベージアウト」というフレーズをよく耳にします。要件を満たすためにごみを渡された場合、停止し、質問をするのはあなたの倫理的責任であり、真の意図を引き出すのに役立ちます。候補者にインタビューしていて、彼らに不明確な要件を与えた場合、明確化の質問を期待します。


5

コンピューターには無限に大きな変数がないため、一意性を保証することは困難です。実世界のチューリングマシンではできません。

私が見ているように、ここには2つの問題があり、どちらにも定評のある解決策があります。

  • 並行性。複数のマシンが同時に値を必要とする場合があります。ありがたいことに、最新のCPUには同時実行性が組み込まれており、一部の言語はこれを利用する開発者に優しい機能を提供します。
  • 一意性。一意性を保証することはできませんが、実世界のシステムがすべての一意の値を使い果たすのが非常に困難になるほど大きな値を保持できる任意に大きな変数を持つことができます

Javaでの私のソリューションは次のとおりです。

public class Foo {
  private static BigInteger value = BigInteger.ZERO;
  private static final Lock lock = new ReentrantLock();

  public static BigInteger nextValue() {
    try {
      lock.lock();
      value = value.add(BigInteger.ONE);
      return value;
    }
    finally {
      lock.unlock();
    }
  }
}

BigIntegerは、任意のサイズの整数型です。無限ではないにしても、非常に大きな値を保持するために大きくなる可能性があります。ロックにより同時実行性が確保されるため、別々のスレッドで処理される2つの同時要求によって同じ値を2回返すことはできません。


コードは500年未満しか使用されないという仮定は有効な仮定だと思います。64ビットストレージで増加する値を単純に返す場合、かなり長い間問題ありません。584555年で、1人あたり1コールで。
Mooingダック14年

1
少なくともJavaでは、2 ^ 63の値です(その半分の長さです)。私たちがお互いを殺す傾向があることを考えると、人類よりもさらに長く存在する可能性があります。とにかく、私はより理論的なアプローチを取りました。現実的には、64(または63)ビットで十分です。

1
@スノーマン:何?!?ソリューションは25万年間のみ有効ですか?!?!?次の候補!!!!!! :-)
ボブジャービス-モニカの復活2014年

0

サーバーのポートを介して関数を公開します。関数を呼び出すために、要求側のマシンは接続を要求し、接続を許可されると同時に、識別コード(簡単にするために連続番号)が割り当てられます。一意の値を要求するポートにメッセージが送信されるたびに、現在の日時のMD5ハッシュと識別コードのMD5ハッシュを連結することにより、値が生成されます。

防弾ソリューションをさらに必要とする場合は、すべてが曖昧になるのではなく、実際の要件を指定する必要があります。


-1
string uniq(string machine_id) 
{
   static long u = long.MinValue;
   Interlocked.Increment(ref u);

   //Time stamp with millisecond precison
   string timestamp = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff",
                                            CultureInfo.InvariantCulture);

   return machine_id + "-" + timestamp + "-" + u;
}

上記の方法で、再起動がある場合でも、異なるマシンから同時に呼び出された場合でも、戻り値が異なることを確認できます。


プログラマは、概念的な質問と回答は、物事を説明することが期待されています。説明の代わりにコードダンプをスローすることは、コードをIDEからホワイトボードにコピーするようなものです。見た目がよく、時には理解できるかもしれませんが、奇妙に感じます...ただ奇妙です。ホワイトボードは、コンパイラがない
ブヨ

おかげでそれを指摘するためにGNAT、次回から解決策を説明するために世話をします
techExplorer
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.