2016-11-23 8 views
1

私は定期的にURLのリストを作成し、そのWebサイトのパフォーマンスをテストするプロセスを実行しています。私の主なプログラムは、基本的にdo ... sleep ... whileループで関数を呼び出し、runTest()をN秒ごとに実行し、キーボードの割り込みで終了させます。基本的にダウンパレー、次のように私のコードは次のとおりです。タスクがキャンセルされないのはなぜですか?

public void runTest() 
{ 
    if(isRunning) 
    { 
     return; //Plus some logging that one or more of the tests hasn't completed 
    } 
    try { 
     isRunning = true; 
     Curl.GlobalInit((int)CURLinitFlag.CURL_GLOBAL_ALL); 
     CancellationTokenSource cts = new CancellationTokenSource(httpTimeoutValueMs * 2); 
     foreach (var url in urls) 
      taskList.Add(doAsyncCurls(url, cts)) 
     List<CurlResults> listOfResults = Task.WhenAll(taskList.Select(x => x)).Result.ToList(); 
     taskList.Clear(); 
    } 
    catch {/*Some exception handling code*/} 
    finally { 
    isRunning = false; 
    Curl.GlobalCleanup(); 
    } 
} 
private static async Task<CurlResults> doAsyncCurls(string url, CancellationTokenSource cts) 
{ 
    try 
    { 
     /*Initiate a Curl using libCurl*/ 
     Easy easy = new Easy(); 
     easy.SetOpt(CURLoption.CURLOPT_URL, url); 
     easy.SetOpt(CURLoption.CURLOPT_DNS_CACHE_TIMEOUT, 0); //Disables DNS cache 
     easy.SetOpt(CURLoption.CURLOPT_CONNECTTIMEOUT, httpTimeoutValueMs/1000); //20sec timeout 

     Task t = new Task(() => easy.Perform(), cts.Token); 
     t.Start(); 
     await t; 
     return new CurlResults(/*valid results parameters*/); 
    } 
    catch (TaskCanceledException) 
    { /*Cancellation token invoked*/ 
     return new CurlResults(/*Invalid results parameters*/); 
    } 
    catch (Exception e) 
    { /*Other exception handling*/ 
     return new CurlResults(/*Invalid results parameters*/); 
    } 

HTTPリクエストように「doAsyncCurl」機能は、キャンセルトークンの半分へのHTTPタイムアウト値を設定し、それは錫で言うことありませんキャンセルトークンが呼び出される前に蒸発して、否定的な結果を生成する必要があります。キャンセルトークンを追加して、以下のように私の問題を解決しようとしました。

私はこれまで何度も実行していますが、すべてがうまくいきますが、最終的に(定期的なrunTest()呼び出しで何百回も繰り返されても何百回も繰り返されています)、タスクの1つが停止し、カールテストプロセスが事実上止まっています。

どのURLに問題がありますか(またすべてのURLは有効です)、何がうまくいかないのかを診断するために何ができるのですか?それとも、私のパラレル・カールを完全に間違って構築したのですか? (私は前回のラウンドから終了したURLに新しいCurlsをインスタンス化し、新しいバッチを開始する前にそれらをすべて終了するのではなく、ぶら下げたままにしておくことに感謝するが、その効率については気にしない利得)。

+3

トークンへの参照を渡しても、タスク本体の自動タスクキャンセルは意味しません。それでも定期的にチェックする必要があります。 http://stackoverflow.com/questions/3712939/cancellation-token-in-task-constructor-why?rq=1 – MickyD

+0

OK - 私はキャンセルトークンの実装を打ち上げましたが、私はまた理由について混乱していますCurlはタイムアウトしていません。 – JetSetJim

答えて

3

キャンセルには自動翻訳はありません。キャンセルのステータスを確認して実行を終了するか、またはキャンセルを実行するにはCancellationToken.ThrowIfCancellationRequestedを呼び出す必要があります。 CancellationTokenは、のキャンセルが要求された場合、を通知します。 自体はのキャンセルが必要です。あなたは、タスクコンストラクタにトークンを渡している

Task t = new Task(() => easy.Perform(), cts.Token); 

次の行は、あなたの問題です。キャンセルが発生した場合は、の前にのタスクが開始されます。タスクが開始されると、実行されたメソッドはキャンセルを行います。 easy.Perform()はキャンセルトークンについて知らないため、キャンセルが要求されたかどうかを決して判断できません。したがって、それは終わりまで走ります。

タスクの実行中にキャンセルトークンを定期的にチェックして、必要なものを達成する必要があります。

+0

でも、この行の後に、トークンを気にすることなく "await t"を使用するのではなく、 "t.wait(timoutMs)"を使用する必要がありますか? – JetSetJim

+0

はい、できますが、それはあなたの仕事を終了させません。それはまだ終わりに向かう。 – Sefe

+0

@JetSetJimこれを行うと、コードは非同期ではありません。あなたは新しいタスクを構築することができます。 [この](http://stackoverflow.com/a/20248663/1159478)のようなものを使用して、取り消しトークンが取り消されたときに終了するタスクを作成することはできますが、これにより操作が中断されることはありません...それがあなたのために十分であれば、それが何をしたいのか。 – Servy

関連する問題