【问题标题】:How to distinquish concurrent progress bar requests on server side in asp.net如何在asp.net中区分服务器端的并发进度条请求
【发布时间】:2012-07-19 02:09:20
【问题描述】:

我实现了进度条,以便在后台处理视频时向用户显示完成状态。它在单个实例上运行良好。但是当两个并发视频进程开始时混淆了。

当两个不同的用户同时启动两个视频进程时,两个用户都会看到视频进程 1 的混合进度状态,有时另一个。

服务器端的视频进程使用静态变量启动。

public static MediaHandler _mhandler = new MediaHandler();

通过

发送到页面的进度指示
[WebMethod]
public static string GetProgressStatus()
{
    return Math.Round(_mhandler.vinfo.ProcessingCompleted, 2).ToString();
}

进度条每隔几秒发送一次进度请求。

现在我的问题是如何设置一次只能针对一个实例的媒体处理程序对象。

例如,进度条 01 仅显示视频进程 01 的状态

进度条 02 仅显示视频进程 02 的状态

【问题讨论】:

  • 什么是MediaHandler?我在 MSDN 中找不到任何有关它的信息
  • 其第三方 .net ffmpeg 包装器,在后台处理视频并发送进度完成状态。
  • 在这种情况下,在你的问题中说清楚......不能指望人们知道这样的信息!
  • 问题与媒体处理程序无关,它与静态对象及其并发请求问题有关。
  • 本例中可能就是这种情况,但在计算中无法正常工作的原因有很多,你不想打折任何可能性。如果您不想想让自己和那些试图回答的人感到困难,请从一开始就提供尽可能多的信息

标签: c# asp.net


【解决方案1】:

我建议您为每个将用于编码生命周期的新编码请求生成一个Guid。另外我建议MediaHandler 不是静态的,并且你的 new() 为每个编码任务增加一个。 GetProgressStatus() 现在应该有一个 Guid 参数,以便您可以查询每个编码的进度。

您将需要持久性(数据库、静态列表、MSMQ...等)来跟踪您的 MediaHandler 实例和或当前处理编码的进度(如果它是串行完成的)。

【讨论】:

  • 感谢生成 Guid 并在每个进程中附加 guid 值解决了我的问题。我在单独的答案中发布了完整的详细信息。
【解决方案2】:

小心使用 ASP.NET 和静态 - 静态 whatchagot 在同一应用域内的会话(用户)之间是全局的(根据类型给予或采取一些差异)。

将用户信息保存在会话存储中。或者,有点疯狂,有一个静态媒体处理程序对象使用会话 ID 处理多个会话,并使用会话 ID 查询其进度。虽然这听起来有点臭,但可能是您想要的,除非您希望每个会话都能够产生自己的编码。

请参阅this answer(有关该主题的众多内容之一)。然而,微软知识库文章有点太不清楚了。

【讨论】:

  • 如果我是非静态的,那么如何通过进度条请求不时获取进程完成信息。
  • 会话的目的是为用户会话保持持久性。
【解决方案3】:

这是一个非常简单的方法:

您是否考虑过使用静态列表?

列表中的每个项目都是运行后台进程的处理程序的实例。您需要识别每个处理程序,最简单的方法是为每个处理程序使用Guid

这是一个示例工作代码:

输出

如您所见,每个窗口都会触发一个新进程,并且每个窗口都会独立更新

ASPX

<head runat="server">
    <title></title>
    <script type="text/javascript" src="Scripts/jquery-1.7.2.min.js"></script>
    <script type="text/javascript" src="Scripts/jquery.timer.js"></script>
    <script type="text/javascript">
        var timer;
        var currentProcess;
        function getProgress() {
            $.ajax({
                url: 'LongTimeOperations.aspx/GetStatus',
                data: '{"processID": "' + currentProcess + '"}',
                contentType: 'application/json; charset=utf-8;',
                dataType: 'json',
                type: "POST",
                async: true,
                cache: false,
                success: function (msg) {
                    $("#res").append("<br/>" + msg.d);
                    var r = msg.d;
                    if (typeof (r) === 'undefined' || r === null) {
                        timer.stop();
                    }
                },
                error: function (hxr) {
                    alert(hxr.responseText);
                }
            });
        }
        $(function () {
            $("#start").click(function () {
                $.ajax({
                    url: 'LongTimeOperations.aspx/StartProcess',
                    data: '{}',
                    contentType: 'application/json; charset=utf-8;',
                    dataType: 'json',
                    type: "POST",
                    async: true,
                    cache: false,
                    success: function (msg) {
                        alert(msg.d);
                        currentProcess = msg.d;
                        timer = $.timer(getProgress, 2000, true);
                    },
                    error: function (hxr) {
                        alert(hxr.responseText);
                    }
                });
            });
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <input type="button" id="start" value="Start Process" />
        <p>
            <div id="res"></div>
        </p>
    </div>
    </form>
</body>

后面的代码

    public static List<CurrentProcess> Processes = new List<CurrentProcess>();

    [WebMethod]
    public static Guid StartProcess()
    {
        Mutex mutex = new Mutex();
        mutex.WaitOne();

        var star = Thread.CurrentThread.ManagedThreadId.ToString();
        var p = new CurrentProcess(Guid.NewGuid());
        Processes.Add(p);

        var o = Observable.Start(() =>
        {
            var cap = p;
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(2000);
                var cp = Processes.FirstOrDefault(x => x.ID == cap.ID);

                if (cp != null)
                    cp.Status = string.Format("Current Process ID: {0}, Iteration: {1}, Starting thread: {2}, Execution thread: {3}",
                        cp.ID.ToString(),
                        i.ToString(),
                        star,
                        Thread.CurrentThread.ManagedThreadId.ToString()
                        );
            }
            Processes.RemoveAll(x => x.ID == cap.ID);
        }, Scheduler.NewThread);

        mutex.ReleaseMutex();
        mutex.Close();

        return p.ID;
    }

    [WebMethod]
    public static string GetStatus(Guid processID)
    {
        var p = Processes.FirstOrDefault(x => x.ID == processID);

        if (p != null)
            return p.Status;

        return null;
    }
}

public class CurrentProcess
{
    public Guid ID { get; set; }

    public string Status { get; set; }

    public CurrentProcess (Guid id)
    {
        this.ID = id;
    }
}

使用的库

在这个示例中,我使用 Rx 创建一个新线程,您可以将其更改为使用其他方法

【讨论】:

    【解决方案4】:

    感谢分享想法,但不幸的是,在使用几乎所有用户共享的静态对象的情况下,没有解决方案解决并发问题。现在我做了一些调整,解决了我的问题。

    我没有使用单个静态对象,而是使用通用列表对象将所有并发进程对象存储在列表中。这是代码。

    public static List<MediaHandler> _lst = new List<MediaHandler>();
    

    其中 MediaHandler 是负责处理视频的类名。

    以下函数负责启动视频处理

    public static string EncodeVideo(string Source, string Published)
    {   
     MediaHandler _mhandler = new MediaHandler(); 
     ..............
     ..............
     _mhandler.vinfo.ProcessID = Guid.NewGuid().ToString(); 
    // unique guid to attach with each process to identify proper object on progress bar and get info request
    // add media handler object in concurrent static list
     _lst.Add(_mhandler);
     return _mhandler.vinfo.ProcessID; // retuned unique identifier
    }
    

    现在必须将每个进度条请求进程 ID 发送给函数,以便发送正确视频处理对象的进度状态。

    [WebMethod]
    public static string GetProgressStatus(string ProcessID)
    {
        string completed_process = "0";
        if (_lst.Count > 0)
        {
            int i = 0;
            for (i = 0; i <= _lst.Count - 1; i++)
            {
                if (_lst[i].vinfo.ProcessID == ProcessID)
                {
                    completed_process = Math.Round(_lst[i].vinfo.ProcessingCompleted, 2).ToString();
                }
            }
        }
    
        return completed_process;
    }
    

    一旦处理完成 100%,只需将所有视频信息存储在对象中,并从静态并发列表中删除媒体处理程序对象。

    if (_lst[i].vinfo.ProcessingCompleted >= 100)
    {
        // remove from list of corrent processes if processes reach this point
        // store all information of completed process and remove it from list of concurrent processes
        // e.g
        VideoInfo current_uploaded_video_info = _lst[i].vinfo;
         _lst.Remove(_lst[i]);
    }
    

    通过这种方式,无限数量的并发进程和进度条请求成为可能。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-07
      • 2012-12-14
      • 1970-01-01
      • 2013-11-23
      • 2016-02-27
      • 2018-10-01
      • 1970-01-01
      • 2015-08-08
      相关资源
      最近更新 更多