2016-08-15 14 views
2

Nancy APIを使用してC#アプリケーションを構築しています。私は時々ユーザーによってキャンセルされる必要がある非常に長さの最適化アルゴリズムを実行する非同期操作を持っています。擬似コードは次のように:ルート内のタスクをキャンセルする

 Get["/algorithm/run/", true] = async (parameters, ct) => 
     { 
       var algy = new Algorithm(); 
       var result = await Task.Run(() => algy.RunAlgorithm(ct), ct); 
     }; 

どのように私はCancellationToken(CT)をキャンセル、またはアルゴリズムをキャンセルする新しい方法を作成して行くのですか?

私が試してみました代替のようなものです:

var cts = new CancellationTokenSource();  
var cToken = cts.Token; 

    Get["/algorithm/run/", true] = async (parameters, ct) => 
    { 
     var algy = new Algorithm(); 
     var result = await Task.Run(() => algy.RunAlgorithm(cToken), cToken); 
    }; 


    Get["/schedule/stop"] = _ => 
    { 
     cts.Cancel(); 
    }; 

しかしルートは独自の非同期タスクであるので、これは明らかに動作しません。

私はここに掲載の記事読みました:

をCancellationTokenがそのように、あなたが協力し、あなたのルートハンドラで処理をキャンセルするかどうかを判断するためにct.IsCancellationRequestedプロパティを確認することができますに渡されます言及http://blog.jonathanchannon.com/2013/08/24/async-route-handling-with-nancy/ を。このプロパティは、たとえば内部エラーがある場合や、ミドルウェアが要求を取り消すことを決定した場合、またはホストがシャットダウンしている場合などに設定できます。もしあなたがナンシーがOWINに準拠していることを知らなかったら、OWINの仕様が出て以来ずっとありました。

私はスレッドを扱うのが初めてであるので、助けていただければ幸いです。

全例:

using Nancy; 
using Nancy.Hosting.Self; 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Net.Http; 
using System.Text; 
using System.Threading; 
using System.Threading.Tasks; 

namespace NancyApp 
{ 
class Program 
{ 
    private static NancyHost NancyHost { get; set; } 
    private static HttpClient Client { get; set; } 

    static void Main(string[] args) 
    { 
     var configuration = new HostConfiguration() 
     { 
      UrlReservations = new UrlReservations() { CreateAutomatically = true } 
     }; 

     NancyHost = new NancyHost(configuration, new Uri("http://localhost:1234")); 

     NancyHost.Start(); 

     Client = new HttpClient(); 
     Client.Timeout = new TimeSpan(1, 0, 0); 
     Client.BaseAddress = new Uri("http://localhost:1234"); 

     Console.WriteLine("Hosting...\n"); 

     Client.GetAsync("http://localhost:1234/run"); 
     System.Threading.Thread.Sleep(5000); 
     Client.GetAsync("http://localhost:1234/cancel"); 
     Console.ReadLine(); 
    } 
} 

public class TestModule : NancyModule 
{ 
    CancellationTokenSource cts = new CancellationTokenSource(); 

    public TestModule() 
    { 
     Get["/run", true] = async (parameters, ct) => 
     { 
      Algorithm ag = new Algorithm(); 
      Console.Write("Running Algorithm...\n"); 
      var result = await Task.Run(() => ag.RunAlgorithm(cts.Token), cts.Token); 

      return Response.AsText(result.ToString()); 
     }; 

     Get["/cancel"] = _ => 
     { 
      Console.Write("Cancel requested recieved\n"); 
      cts.Cancel(); 
      return Response.AsText("Foo"); 
     }; 

    } 
} 

class Algorithm 
{ 
    public Algorithm() 
    { 

    } 

    public int RunAlgorithm(CancellationToken cToken) 
    { 
     int min = Int32.MinValue; 

     while (min < Int32.MaxValue) 
     { 
      if (!cToken.IsCancellationRequested) 
      { 
       min++; 
      } 
      else 
      { 
       Console.Write("IsCancellationRequested true!\n"); 
       cToken.ThrowIfCancellationRequested(); 
      } 
     } 
     return min; 
    } 
} 
} 
+0

私にはナンシーは分かりませんが、それはあなたに渡す独自のトークンを持っているようです。それでも、トークンを1つしかチェックしないようにする必要はありません。渡したものと作成したものを使用し、_either_が設定されている場合は取り消すことができます。詳細が必要な場合は、質問を改善して、良い[mcve]が含まれるようにしてください。具体的に何が問題になっているかはっきりしています。上のコード例では、特にハードルとして明白なようなものは見られません。 'CreateLinkedTokenSource()'を使うと、一度に2つのトークンの使用を簡単にすることができます。 –

+0

2番目の例でもっと明確にする:私はcts.Cancel()を呼び出すと、これがうまくいくと思いましたが、私のalgy.RunAlgorithm(cToken)内でcToken.IsCancellationRequestedを呼び出すと、cTokenオブジェクトはtrueを返しません。 – Phrank

+0

_ "私がcts.Cancel()を呼び出すと、cTokenオブジェクトはtrueを返すことはありません。私のalgy.RunAlgorithm(cT oken)内のcToken.IsCancellatio nRequestedを呼び出すと、" _ - それはそうではありません。起こっていることは、その行動を確実に再現する良い[mcve]によって本当にサポートされなければならない種類の主張です。あなたが 'RunAlgorithm()'に渡したのと同じトークンを取り消したと思って、代わりに2つの異なるものを扱っていると思う可能性は非常に高いです。しかし、良いMCVEがなければ、問題の修正方法を提案することはできません。 –

答えて

0

作業を訂正:支援のための@Peter Dunihoへ

public class TestModule : NancyModule 
{ 
    static CancellationTokenSource cts = new CancellationTokenSource(); 
    static CancellationToken cToken = cts.Token; 

    public TestModule() 
    { 
     Get["/run", true] = async (parameters, ct) => 
     { 
      Algorithm ag = new Algorithm(); 
      Console.Write("Running Algorithm...\n"); 
      var result = await Task.Run(() => ag.RunAlgorithm(cToken), cToken); 

      return Response.AsText(result.ToString()); 
     }; 

     Get["/cancel"] = _ => 
     { 
      Console.Write("Cancel requested recieved\n"); 
      cts.Cancel(); 
      cts.Dispose(); 
      cts = new CancellationTokenSource(); 
      cToken = cts.Token; 
      return Response.AsText("Cancelled!"); 
     }; 
    } 
} 

感謝。

関連する問題