0

NancyModuleGetメソッドを介して呼び出される長時間実行プロセスがあります。プロセスの実行中にブラウザーがハングするのではなく、この呼び出しを非同期にします。つまり、Getメソッドをすぐに返し、長時間実行されているプロセスにその処理を任せます。その後、定期的にプロセスのステータスを確認し、それに応じて行動することができました。

私はC#5の非同期/待機機能に不慣れですが、これらはまさにこの種のタスクのためのものであると確信しています。以下のコードは私の試みを示しています。期待どおりに非同期で実行されていないことを示すロギングをいくつか入れました。代わりに、長時間実行されるプロセスがGetメソッドをブロックするため、ブラウザーがハングします。

モジュール

public class TestModule : NancyModule
{            
    public TestModule(ITestService testService)
    {
        Get["/longprocess"] = _ =>
            {
                Log.Write("Module : Start");
                testService.LongProcess();
                Log.Write("Module : Finish");
                return HttpStatusCode.OK;
            };
    }
}

サービス

public interface ITestService
{
    Task<bool> LongProcess();
}

public class TestService : ITestService
{
    public async Task<bool> LongProcess()
    {
        await LongProcessAsynch();
        return true;
    }

    private Task<bool> LongProcessAsynch()
    {
        Log.Write("LongProcess : Start");
        Thread.Sleep(5000);
        //Task.Delay(5000); <- Has same effect
        Log.Write("LongProcess : Finish");
        return true.AsTask();
    }
}

拡張方法

public static Task<T> AsTask<T>(this T candidate)
{
    var source = new TaskCompletionSource<T>();
    source.SetResult(candidate);
    return source.Task;
}

ログ出力

14/06/2012 19:22:29 : Module : Start
14/06/2012 19:22:29 : LongProcess : Start
14/06/2012 19:22:34 : LongProcess : Finish
14/06/2012 19:22:34 : Module : Finish

上記のログ出力から、LongProcess()がGetモジュールの戻りをブロックしていることがわかります。タスクが非同期で実行されている場合、ログは次のようになります。

期待されるログ

Module : Start
LongProcess : Start
Module : Finish
LongProcess : Finish

await実際に必要なのは、NancyModuleGetメソッドに入れることだと思います。以下のコードのようなものかもしれませんが、モジュールコンストラクターをとしてマークすることができず、Getメソッド内でasnyc使用できないためawait(または現在信じている) 、これを行うことはできません

Get["/longprocess"] = _ =>
    {
        Log.Write("Module : Start");
        await testService.LongProcess();
        Log.Write("Module : Finish");
        return HttpStatusCode.OK;
    }; 

ヘルプ、例、またはリソースへのポインタをありがとう。

編集1

asyncさらなる調査により、asp.netはデフォルトで積極的に通話を阻止しているように見えることが明らかになっています。とは何か、Sessionそしてそれが非UIスレッドを処理する方法と関係があると私は信じています。だから私は私のweb.configに以下を追加しました(以下を参照)

  • UseTaskFriendlySynchronizationContext
  • enableSessionState = "false"

残念ながら、それは何の違いもありません、そして、私のasync/await呼び出しLongProcess()はまだブロックしています。

<configuration>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
    <add key="webPages:Enabled" value="false" />
  </appSettings>
  <system.web>
    <httpRuntime targetFramework="4.5"/>
    <pages controlRenderingCompatibilityVersion="4.0" enableSessionState="false" />
    ... more config
</configuration>
4

2 に答える 2

1

私は C#5 の async / await 機能は初めてですが、これらはこの種のタスクだけを対象としていると確信しています。

いいえ。async/は、単一プロセスのコンテキスト内でawait非同期プログラミングを容易にすることを目的としています。これらは、HTTP 通信の性質を変更しません。

ASP.NET サーバーで (HTTP 要求のコンテキストで)を使用するawaitと、ASP.NET スレッドがスレッド プールに返されます。ただし、ASP.NET は HTTP 要求が完了していないことを認識しているため、クライアント (ブラウザー) への応答を完了しません。

これは仕様によるものです。

必要なことを行うには、AJAX、SignalR、またはその他のソリューションを使用する必要があります。

于 2012-06-15T13:54:58.540 に答える