8

3つのクラスファイルで3つの非同期リクエストを送信する必要があります。3つのリクエストの応答時間は異なります。最初のリクエストは2秒、2番目のリクエストは7秒、3番目のリクエストは4秒です。これで、最初の応答を2秒以内にブラウザに表示する必要があります。 3番目の応答と最後に2番目の応答が表示されますが、私の結果では、3つの応答が完了した後、一度にすべての応答が表示されます。提案をお願いします。非常に緊急です。

私のコードは

public delegate string AsyncMethodCaller(string name);
        public delegate string AsyncMethodCallertest(string name);
        public delegate string NatilusAsyn(string name);

ボタンクリックイベント

     AsyncMethodCaller caller = new AsyncMethodCaller(ps.PennStarService);
        IAsyncResult result = caller.BeginInvoke(txtFirst.Text, null, null);
    NatilusAsyn caller123 = new NatilusAsyn(cs.PennStarService);
        IAsyncResult result123 = caller123 .BeginInvoke(txtthird.Text, null, null);
        AsyncMethodCallertest cltest = new AsyncMethodCallertest(ps.testHi);
        IAsyncResult tetsresult = cltest.BeginInvoke(txtSecond.Text, null, null);
        lblFirst.Text = caller.EndInvoke(result);           
        lblSecond.Text = cltest.EndInvoke(tetsresult);
     lblthird.Text = caller123.EndInvoke(result123); 

ありがとうヘマンス

4

1 に答える 1

5

問題の根本は、ASP.Net要求で何が起こるかを理解することだと思います。

各ページには、イベントのパイプラインを含むライフサイクルがあります。詳細については、この回答を確認してください。各リクエストは、現在のアプリケーションのAppDomainからのワーカースレッドによって処理されます。ページパイプラインが完了するまで、応答はユーザーに送信されません。

スレッドについて:

同時に使用可能なスレッドの数は、で構成できますmachine.config。理解しておくべき重要な点は、これらのスレッド数は固定されているということです。つまり、同時スレッドの最大数に達すると、後続のリクエストはキューに入れられ、キューに入れることができるリクエストの数はわずかになります。サーバーのメモリによって制限されます。

ワーカースレッドが時間のかかる操作を呼び出すと、操作が終了するまでそのスレッドをブロックします。つまり、複数の同時ユーザーがいる場合は、使用可能なすべてのスレッドがブロックされ、新しいリクエストが強制的に配置される可能性があります。キューに入れられ、最悪の場合、503エラーが発生します-サービスを利用できません。

これを防ぐ方法は、バックグラウンドスレッドでこれらの種類のメソッドを呼び出すことです。コードと同様ですが、この場合の動作は期待どおりではありません。コードは、ページリクエストを完了するためにスレッドが終了するのを待っています。これが、同時に結果を受け取る理由です(最後に)リクエストの)。

asp.netページを非同期で実行する方法の詳細については、この優れた記事を参照してください。

今、あなたが必要とする結果を得るために:

(これは完全に機能する例です。この例では、Rx-リアクティブプログラミングを使用して、新しいスレッドで時間のかかる長いメソッドを実行しています。必要に応じて、これを変更して別のフレームワークを使用できます。 APIをより快適に)

PageMethodsの使用

背後にあるコード

    [WebMethod]
    public static string Execute1()
    {
        JavaScriptSerializer j = new JavaScriptSerializer();
        string r = string.Empty;
        var o = Observable.Start(() =>
            {
                Thread.Sleep(2000);
                r = "My Name1: " + DateTime.Now.ToString() + " Background thread: " + Thread.CurrentThread.ManagedThreadId.ToString();
            }, Scheduler.NewThread);
        o.First();
        r += " Main thread: " + Thread.CurrentThread.ManagedThreadId.ToString();
        r = j.Serialize(new { res = r });
        return r;
    }

    [WebMethod]
    public static string Execute2()
    {
        JavaScriptSerializer j = new JavaScriptSerializer();
        string r = string.Empty;
        var o = Observable.Start(() =>
        {
            Thread.Sleep(7000);
            r = "My Name2: " + DateTime.Now.ToString() + " Background thread: " + Thread.CurrentThread.ManagedThreadId.ToString();
        }, Scheduler.NewThread);
        o.First();
        r += " Main thread: " + Thread.CurrentThread.ManagedThreadId.ToString();
        r = j.Serialize(new { res = r });
        return r;
    }

    [WebMethod]
    public static string Execute3()
    {
        JavaScriptSerializer j = new JavaScriptSerializer();
        string r = string.Empty;
        var o = Observable.Start(() =>
        {
            Thread.Sleep(4000);
            r = "My Name3: " + DateTime.Now.ToString() + " Background thread: " + Thread.CurrentThread.ManagedThreadId.ToString();
        }, Scheduler.NewThread);
        o.First();
        r += " Main thread: " + Thread.CurrentThread.ManagedThreadId.ToString();
        r = j.Serialize(new { res = r });
        return r;
    }

ASPX

....
<script type="text/javascript" src="Scripts/jquery-1.7.2.min.js"></script>
....
<asp:ScriptManager runat="server" />
<input type="button" id="callAsync" name="callAsync" value="Call Async" />
<div id="first"></div>
<script type="text/javascript">
    function onsuccess1(msg) {
        var result = Sys.Serialization.JavaScriptSerializer.deserialize(msg.d);
        var h = $("#first").html();
        $("#first").html( h + "<br/>&nbsp;&nbsp;&nbsp;&nbsp;Result: " + result.res);
    }
    function onerror1(xhr) {
        alert(xhr.responseText);
    }
    function callMyMethod(url, mydata, onsuccess, onerror) {
        var h = $("#first").html();
        $("#first").html(h + "<br/>&nbsp;&nbsp;Calling Method: " + new Date());
        return $.ajax({
            cache: false,
            type: "POST",
            async: true,
            url: url,
            data: mydata, 
            contentType: "application/json",
            dataType: "json",
            success: function (msg) {
                onsuccess(msg);
            },
            error: function (xhr) {
                onerror(xhr);
            }
        });
    }
    $(document).ready(function () {
        $("#callAsync").click(function () {
            var h = $("#first").html();
            $("#first").html(h + "<br/>New call: " + new Date());
            callMyMethod("DynamicControls.aspx/Execute1", "{}", function (data) { onsuccess1(data); }, function (data) { onerror1(data); });
            callMyMethod("DynamicControls.aspx/Execute2", "{}", function (data) { onsuccess1(data); }, function (data) { onerror1(data); });
            callMyMethod("DynamicControls.aspx/Execute3", "{}", function (data) { onsuccess1(data); }, function (data) { onerror1(data); });
        });
    });
</script>

出力

このコードは以下を生成します:

New call: Fri Jun 22 02:11:17 CDT 2012
  Calling Method: Fri Jun 22 02:11:17 CDT 2012
  Calling Method: Fri Jun 22 02:11:17 CDT 2012
  Calling Method: Fri Jun 22 02:11:17 CDT 2012
    Result: My Name1: 6/22/2012 2:11:19 AM Background thread: 38 Main thread: 48
    Result: My Name2: 6/22/2012 2:11:26 AM Background thread: 50 Main thread: 48
    Result: My Name3: 6/22/2012 2:11:30 AM Background thread: 52 Main thread: 48

コードが最適化されていないことがわかるように、メインスレッドはロックされており、設定した最大秒数は7秒ですが、この場合、サーバーコードが呼び出されたとき(02:11:17)から最後まで受信した応答(2:11:30)13秒が経過しました。これは、ASP.NetがデフォルトでSession、メインスレッドをロックしている現在のオブジェクトをロックするためです。この例ではセッションを使用していないため、次のようにページを構成できます。

<%@ Page EnableSessionState="False"

そして、新しい出力は次のとおりです。

New call: Fri Jun 22 02:13:43 CDT 2012
  Calling Method: Fri Jun 22 02:13:43 CDT 2012
  Calling Method: Fri Jun 22 02:13:43 CDT 2012
  Calling Method: Fri Jun 22 02:13:43 CDT 2012
    Result: My Name1: 6/22/2012 2:13:45 AM Background thread: 52 Main thread: 26
    Result: My Name3: 6/22/2012 2:13:47 AM Background thread: 38 Main thread: 49
    Result: My Name2: 6/22/2012 2:13:50 AM Background thread: 50 Main thread: 51

これで、最初のサーバーメソッド呼び出しからメインスレッドをロックせずに受信した最後の応答までわずか7秒が経過しました=)

編集1

私の理解が正しければ、いくつかのパラメーターをメソッドに渡し、データセットを返してラベルとテキストボックスを埋める必要があります。

PageMethodsにパラメーターを渡すには、次の方法があります。

これらのNugetパッケージをインストールします。

コマンドクラス。このクラスは、postアクションでサーバーメソッドに送信するパラメーターを表します

public class ProcessXmlFilesCommand
{
    public string XmlFilePath { get; set; }

    public ProcessXmlFilesCommand()
    {
    }
}

を返す代わりに、次のように、DataSetを返す方が簡単で管理しやすいと思います。IEnumerable

    [WebMethod]
    public static IEnumerable<MyResult> ProcessXmlFiles(ProcessXmlFilesCommand command)
    {
        List<MyResult> results = new List<MyResult>();
        var o = Observable.Start(() =>
        {
            // here do something useful, process your xml files for example
            // use the properties of the parameter command
            results.Add(new MyResult { SomethingInteresting = DateTime.Now.ToString(), FilePath = command.XmlFilePath + "Processed" });
            results.Add(new MyResult { SomethingInteresting = DateTime.Now.ToString(), FilePath = command.XmlFilePath + "Processed" });
            results.Add(new MyResult { SomethingInteresting = DateTime.Now.ToString(), FilePath = command.XmlFilePath + "Processed" });
            Thread.Sleep(2000);
        }, Scheduler.NewThread);
        o.First();
        return results.AsEnumerable();
    }

クラスはMyResult、ユーザーに送り返すデータを表します

public class MyResult
{
    public string SomethingInteresting { get; set; }
    public string FilePath { get; set; }
}

ASPXページで

<script type="text/javascript" src="Scripts/jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="Scripts/json2.min.js"></script>


    <script type="text/javascript">
        function processFiles() {
            var filePath = $("#filePath").val();
            var command = new processFilesCommand(filePath);
            var jsonCommand = JSON.stringify(command);

            $.ajax({
                cache: false,
                type: "POST",
                async: true,
                url: "CustomThreads.aspx/ProcessXmlFiles",
                data: "{'command':" + jsonCommand + "}",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (msg) {
                    onFileProcessedSuccess(msg);
                },
                error: function (exc) {
                    onFileProcessedError(exc);
                }
            });
        }
        function onFileProcessedSuccess(msg) {
            var response = msg.d;
            $.each(response, function (index, myResponse) {
                $("#<%:this.myLabel.ClientID %>").append(myResponse.SomethingInteresting + "<br/>");
            });
        }
        function onFileProcessedError(exc) {
            alert("Error: " + exc.responseText);
        }
        function processFilesCommand(filePath) {
            this.XmlFilePath = filePath;
        }
        $(document).ready(function () {
            $("#processFile").click(processFiles);
        });
    </script>

<input type="text" name="filePath" id="filePath" />
<input type="button" name="processFile" id="processFile" value="Process File" />

<br /><asp:Label ID="myLabel" runat="server" />

編集2

これは単純化された方法です

<%@ Page EnableSessionState="False" Language="C#" AutoEventWireup="true" CodeBehind="CustomThreadsSimple.aspx.cs" Inherits="WebApplication1.CustomThreadsSimple" %>
....
<script type="text/javascript" src="Scripts/jquery-1.7.2.min.js"></script>
....
    <script type="text/javascript">
        function makeCall(url, data) {
            $("#<%:this.lblMessage.ClientID %>").append("<br/>Initializing call: " + new Date());
            $.ajax({
                url: url,
                type: "POST",
                dataType: "json",
                contentType: "application/json; charset=utf-8;",
                async: true,
                cache: false,
                data: "{name:'" + data + "'}",
                success: function (msg) {
                    $("#<%:this.lblMessage.ClientID %>").append("<br/>&nbsp;&nbsp;&nbsp;&nbsp;" + msg.d);
                },
                error: function (exc) {
                    alert(exc.responseText);
                }
            });
        }
        $(function () {
            $("#startProcess").click(function () {
                makeCall("CustomThreadsSimple.aspx/Execute1", $("#<%: this.txtData1.ClientID %>").val());
                makeCall("CustomThreadsSimple.aspx/Execute2", $("#<%: this.txtData2.ClientID %>").val());
                makeCall("CustomThreadsSimple.aspx/Execute3", $("#<%: this.txtData3.ClientID %>").val());
            });
        });
    </script>
    <asp:TextBox runat="server" ID="txtData1" />
    <asp:TextBox runat="server" ID="txtData2" />
    <asp:TextBox runat="server" ID="txtData3" />
    <input type="button" name="startProcess" id="startProcess" value="Start execution" />
    <asp:Label ID="lblMessage" runat="server" />

背後にあるコード

public partial class CustomThreadsSimple : System.Web.UI.Page
{
    [WebMethod]
    public static string Execute1(string name)
    {
        string res = string.Empty;
        Func<string, string> asyncMethod = x =>
        {
            Thread.Sleep(2000);
            return "Res1: " + x +" " + DateTime.Now.ToString() + " Background thread: " + Thread.CurrentThread.ManagedThreadId.ToString();
        };

        IAsyncResult asyncRes = asyncMethod.BeginInvoke(name, null, null);
        res = asyncMethod.EndInvoke(asyncRes);
        res += " Main thread: " + Thread.CurrentThread.ManagedThreadId.ToString();
        return res;
    }

    [WebMethod]
    public static string Execute2(string name)
    {
        string res = string.Empty;
        Func<string, string> asyncMethod = x =>
        {
            Thread.Sleep(7000);
            return "Res2: " + x + " " + DateTime.Now.ToString() + " Background thread: " + Thread.CurrentThread.ManagedThreadId.ToString();
        };

        IAsyncResult asyncRes = asyncMethod.BeginInvoke(name, null, null);
        res = asyncMethod.EndInvoke(asyncRes);
        res += " Main thread: " + Thread.CurrentThread.ManagedThreadId.ToString();
        return res;
    }

    [WebMethod]
    public static string Execute3(string name)
    {
        string res = string.Empty;
        Func<string, string> asyncMethod = x =>
        {
            Thread.Sleep(4000);
            return "Res3: " + x + " " + DateTime.Now.ToString() + " Background thread: " + Thread.CurrentThread.ManagedThreadId.ToString();
        };

        IAsyncResult asyncRes = asyncMethod.BeginInvoke(name, null, null);
        res = asyncMethod.EndInvoke(asyncRes);
        res += " Main thread: " + Thread.CurrentThread.ManagedThreadId.ToString();
        return res;
    }
}

出力

ここに画像の説明を入力してください

于 2012-06-22T05:14:42.437 に答える