1

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

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

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

public static MediaHandler _mhandler = new MediaHandler();

进度指示发送到页面通过

[WebMethod]
public static string GetProgressStatus()
{
    return Math.Round(_mhandler.vinfo.ProcessingCompleted, 2).ToString();
}

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

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

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

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

4

4 回答 4

1

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

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

请参阅此答案(有关该主题的众多答案之一)。但是,Microsoft 知识库文章在 imo 中有点太不清楚了。

于 2012-07-17T12:18:08.963 回答
1

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

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

于 2012-07-17T13:01:41.720 回答
1

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

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

列表中的每个项目都是运行后台进程的处理程序的实例。您需要识别每个处理程序,最简单的方法是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 创建一个新线程,您可以将其更改为使用另一种方法

于 2012-07-17T14:28:28.060 回答
1

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

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

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]);
}

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

于 2012-07-18T18:09:20.667 回答