2017-11-16 11 views
2

私はそれを非同期にするために何をすべきメソッドを非同期にするには?

public static LevenshteinMatches LevenshteinSingleThread(this string str, string expression, int maxDistance) { 
     if (str.Length > expression.Length + 1) { 
      int len = expression.Length; 
      long strLen = str.Length - len + 1; 
      int[] results = new int[strLen]; 
      int[][,] dimension = new int[strLen][,]; 
      for (int i = 0; i < strLen; i++) { 
       dimension[i] = new int[len + 1, len + 1]; 
      } 

      string source = str; 
      source = source.ToUpper(); 
      expression = expression.ToUpper(); 

      for (int i = 0; i < strLen; i++) { 
       results[i] = SqueareLevenshtein(ref dimension[i], str.Substring(i, len).ToUpper(), expression, len); 
      } 

      LevenshteinMatches matches = new LevenshteinMatches(); 

      for (int i = 0; i < strLen; i++) { 
       if (results[i] <= maxDistance) { 
        matches.addMatch(str.Substring(i, len), Math.Round((1.0 - ((double)results[i]/len)) * 100.0, 2), i, len, results[i]); 
       } 
      } 

      return matches; 
     } 
     else { 
      LevenshteinMatch match = str.LevenshteinCPU(expression, maxDistance); 
      if (match != null) 
       return new LevenshteinMatches(match); 
      else 
       return new LevenshteinMatches(); 
     } 
    } 

レーベンシュタイン距離を計算するための方法がありますか?

このメソッドを残して、別の方法で呼び出す必要がありますか?

ここでは非同期化しようとしています。何が間違っているのか分かりませんが、結果は得られません。スレッドは動作していますが、数ミリ秒かかるだけです。コードlink

public static async Task<LevenshteinMatches> LevenshteinSingleThread(this string str, string expression, int maxDistance) { 
     return await Task.Factory.StartNew(() => { 
      if (str.Length > expression.Length + 1) { 
       int len = expression.Length; 
       long strLen = str.Length - len + 1; 
       int[] results = new int[strLen]; 
       int[][,] dimension = new int[strLen][,]; 
       for (int i = 0; i < strLen; i++) { 
        dimension[i] = new int[len + 1, len + 1]; 
       } 

       string source = str; 
       source = source.ToUpper(); 
       expression = expression.ToUpper(); 

       for (int i = 0; i < strLen; i++) { 
        results[i] = SqueareLevenshtein(ref dimension[i], str.Substring(i, len).ToUpper(), expression, len); 
       } 

       LevenshteinMatches matches = new LevenshteinMatches(); 

       for (int i = 0; i < strLen; i++) { 
        if (results[i] <= maxDistance) { 
         matches.addMatch(str.Substring(i, len), Math.Round((1.0 - ((double)results[i]/len)) * 100.0, 2), i, len, results[i]); 
        } 
       } 

       return matches; 
      } 
      else { 
       LevenshteinMatch match = str.LevenshteinCPU(expression, maxDistance); 
       if (match != null) 
        return new LevenshteinMatches(match); 
       else 
        return new LevenshteinMatches(); 
      } 
     }); 
    } 

残りそしてそれは、私はそれを呼び出す方法は次のとおりです。

string s = "xcjavxzcbvmrmummuuutmtumuumtryumtryumtrutryumtryumtrymutryumtyumtryumtrmutyumtrurtmutymurtmyutrymut"; 

     s = string.Concat(Enumerable.Repeat(s, 4000)); 

     var watch = System.Diagnostics.Stopwatch.StartNew(); 
     var ret = s.LevenshteinSingleThread("jas", 1); 
     var res = ret.Result; 
     watch.Stop(); 



     var elapsedMs = watch.ElapsedMilliseconds; 
+0

を行うことができ、スレッドセーフである場合。 '.Result'ではなく' 'ret''を待つ必要があります。 – JSteward

+5

*メソッドを非同期にしない*。そのメソッドが行っていることについては、実際には非同期ではありません。 – Servy

+2

あなたのコードはCPUにバインドされていて、非同期に待機しているようです。しかし、特定のホットスポットを並列化することでいくつかの利点が得られますか? – StuartLC

答えて

5

あなたの機能についての非同期何もありませんが、それは完全にCPUバインドされた作品です。シグニチャをasync Task<LevenshteinMatches>に変更し、関数内でawaitを使用しない場合は、コンパイラで警告が発生しているはずです。

あなたが実際に行っていることが並行して動作している場合は、「非同期にする」の代わりに、コードを並列に呼び出します。

string s = "xcjavxzcbvmrmummuuutmtumuumtryumtryumtrutryumtryumtrymutryumtyumtryumtrmutyumtrurtmutymurtmyutrymut"; 
s = string.Concat(Enumerable.Repeat(s, 4000)); 

var expressions = new[] {"jas", "cbv"} 

var tasks = new List<Task<LevenshteinMatches>>() 
foreach(var expression in expressions) 
{ 
    var task = new Task.Run(()=> message.LevenshteinSingleThread(expression, 1)); //Start multiple threads 
    tasks.Add(task); 
} 
LevenshteinMatches[] results = Task.WaitAll(tasks); //Wait for all the threads to end. 

あなたも、あなたが上Addを呼び出す任意のコレクションがどちらかlock内部で同期またはスレッドされていることに注意してください、並列ループのためのいくつかを作るためにParallel.For(を使用することにより、マルチスレッドの内部機能の部分を作ることができます安全なコレクション。例えば

SqueareLevenshteinは内部あなたは、UIの文脈からそのようなコードを呼び出す場合は、おそらくデッドロックしているあなたの第二の例では

Parallel.For(0, strLen, i => { 
            //Are you sure ref is needed here? 
    results[i] = SqueareLevenshtein(ref dimension[i], str.Substring(i, len).ToUpper(), expression, len); 
}); 

LevenshteinMatches matches = new LevenshteinMatches(); 

Parallel.For(0, strLen; i => { 
    if (results[i] <= maxDistance) { 
     lock(matches) 
     { 
      matches.addMatch(str.Substring(i, len), Math.Round((1.0 - ((double)results[i]/len)) * 100.0, 2), i, len, results[i]); 
     } 
    } 
}); 

return matches; 
+0

私は複数のスレッドを別々のスライス上で動作させたいと思っていたのでrefを使用しましたが、今すぐ削除できます – Iluvatar

関連する問題