协助UI Dispatcher处理大量的方法调用

2023-12-14

以下帖子已成为bit*比预期更长*我对此表示歉意,但也许你会发现阅读起来很有趣,也许你有一个想法可以帮助我:)

我正在开发一个小型应用程序,其 GUI 由许多列表控件组成。每个列表控件都有一个thread与之相关的是永久生产正在添加到列表中的字符串。

允许列表控件由不同线程更新我建了一个扩展的 ObservableCollection that 异步调用其所有业务均以用户界面调度程序效果很好。以下是该类的代码片段,用于举例说明插入操作:

public class ThreadSaveObservableCollection<T> : ObservableCollection<T> {

    private int _index;

    private Dispatcher _uiDispatcher;
    private ReaderWriterLock _rwLock;

    // ...

    private bool _insertRegFlag;

    new public void Insert (int index, T item) {

        if (Thread.CurrentThread == _uiDispatcher.Thread) {

            insert_(index, item);
        } else {

            if (_insertRegFlag) { }
            else {

                BufferedInvoker.RegisterMethod(_index + "." + (int)Methods.Insert);
                _insertRegFlag = true;
            }

            BufferedInvoker.AddInvocation(new Invocation<int, T> { Ident = _index + "." + (int)Methods.Insert, Dispatcher = _uiDispatcher, Priority = DispatcherPriority.Normal, Param1 = index, Param2 = item, Method = new Action<int, T>(insert_) });
        }
    }

    private void insert_ (int index, T item) {

        _rwLock.AcquireWriterLock(Timeout.Infinite);

        DateTime timeStampA = DateTime.Now;

        base.Insert(index, item);

        DateTime timeStampB = DateTime.Now;

        BufferedInvoker.Returned(_index + "." + (int)Methods.Insert, timeStampB.Subtract(timeStampA).TotalMilliseconds);

        _rwLock.ReleaseWriterLock();
    }

    // ...
}

为了以一种挂起的调用任务的形式对调用进行建模,我构建了以下内容:

public interface IInvocation {

    string Ident { get; set; }
    void Invoke ();
}

public struct Invocation : IInvocation {

    public string Ident { get; set; }
    public Dispatcher Dispatcher { get; set; }
    public DispatcherPriority Priority { get; set; }
    public Delegate Method { get; set; }

    public void Invoke () {

        Dispatcher.BeginInvoke(Method, Priority, new object[] { });
    }
}

我现在的问题是因为大量我正在 UI 调度程序上调用的方法调用(我有大约 8 到 10 个线程,它们永久生成它们添加到列表中的字符串)UI 失去响应用户 I/O 的能力(例如使用鼠标)大约之后。 30 秒,直到大约一分钟后根本不接受任何用户交互。

为了面对这个问题我写了一些缓冲调用程序它负责缓冲我想要调用到 UI 调度程序的所有方法调用,然后在受控方式例如调用之间有一些延迟避免洪水UI 调度程序。

这是一些代码来说明我在做什么(请参阅代码段后面的描述):

public static class BufferedInvoker {

    private static long _invoked;
    private static long _returned;
    private static long _pending;
    private static bool _isInbalanced;

    private static List<IInvocation> _workLoad;
    private static Queue<IInvocation> _queue;

    private static Thread _enqueuingThread;
    private static Thread _dequeuingThread;
    private static ManualResetEvent _terminateSignal;
    private static ManualResetEvent _enqueuSignal;
    private static ManualResetEvent _dequeueSignal;

    public static void AddInvocation (IInvocation invocation) {

        lock (_workLoad) {

            _workLoad.Add(invocation);
            _enqueuSignal.Set();
        }
    }

    private static void _enqueuing () {

        while (!_terminateSignal.WaitOne(0, false)) {

            if (_enqueuSignal.WaitOne()) {

                lock (_workLoad) {

                    lock (_queue) {

                        if (_workLoad.Count == 0 || _queue.Count == 20) {

                            _enqueuSignal.Reset();
                            continue;
                        }

                        IInvocation item = _workLoad[0];
                        _workLoad.RemoveAt(0);
                        _queue.Enqueue(item);

                        if (_queue.Count == 1) _dequeueSignal.Set();
                    }
                }
            }
        }
    }

    private static void _dequeuing () {

        while (!_terminateSignal.WaitOne(0, false)) {

            if (_dequeueSignal.WaitOne()) {

                lock (_queue) {

                    if (_queue.Count == 0) {

                        _dequeueSignal.Reset();
                        continue;
                    }

                    Thread.Sleep(delay);

                    IInvocation i = _queue.Dequeue();
                    i.Invoke();

                    _invoked++;
                    _waiting = _triggered - _invoked;
                }
            }
        }
    }

    public static void Returned (string ident, double duration) {

        _returned++;

        // ...
    }
}

这背后的想法缓冲调用者那是可观察集合不要单独调用操作,而是调用添加调用的方法缓冲调用者这使得调用任务进入其_工作负载列表。这缓冲调用者然后维护两个“内部”线程,它们在_queue- 一个线程从_工作负载列表并将它们放入_queue另一个线程将调用从_queue最后依次调用它们。

所以这只不过是两个要存储的缓冲区待处理的调用任务为了delay他们的实际调用。我正在进一步数数调用任务实际上已经被调用了_出队线程(即长_invoked)以及从其执行中返回的方法的数量(可观察集合称为回到()的方法缓冲调用者当它完成执行时 - 存储在_回多变的。

我的想法是使用 (_invoked - _回)来感受一下workloadUI 调度程序的 - 但令人惊讶的是_pending总是低于 1 或 2。

所以我现在的问题是,虽然我延迟了对 UI 调度程序的方法调用(使用 Thread.Sleep(delay)),但应用程序在一段时间后开始滞后,这反映了 UI 有太多事情需要处理的事实用户输入/输出。

但是 - 这就是我真正想知道的 -_pendingcounter 永远不会达到高值,大多数时候它是 0,即使 UI 已经被冻结。

所以我现在必须找到

(1)一种测量 UI 调度程序工作负载的方法,以确定 UI 调度程序过度工作的点,以及

(2)做一些反对它的事情。

现在非常感谢您阅读到这里,我希望您有任何想法如何在 UI 调度程序上调用任意大量方法而不压倒它。

先感谢您 ...强调文字*强调文字*


快速浏览了一下,我发现你睡觉时是锁着锁的。这意味着在睡眠时没有人可以入队,从而导致队列无用。

应用程序不会因为队列繁忙而延迟,而是因为锁几乎总是被持有。

我认为您最好删除所有手动实现的队列、锁和监视器,而只使用内置的 ConcurrentQueue。每个 UI 控件和线程一个队列,每个队列一个计时器。

无论如何,这就是我的建议:

ConcurrentQueue<Item> queue = new ...;

//timer pulls every 100ms or so
var timer = new Timer(_ => {
 var localItems = new List<Item>();
 while(queue.TryDequeue(...)) { localItems.Add(...); }
 if(localItems.Count != 0) { pushToUI(localItems); }
});

//producer pushes unlimited amounts
new Thread(() => { while(true) queue.Enqueue(...); });

Simple.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

协助UI Dispatcher处理大量的方法调用 的相关文章

  • 如何使用 openSSL 函数验证 PEM 证书的密钥长度

    如何验证以这种方式生成的 PEM 证书的密钥长度 openssl genrsa des3 out server key 1024 openssl req new key server key out server csr cp server
  • EntityHydrate 任务失败

    我最近安装了 Visual Studio 11 Beta 和 Visual Studio 2010 之后 我无法在 Visual Studio 2010 中构建依赖于 PostSharp 的项目 因此我卸载了 Visual Studio 1
  • C# 中的 Stack<> 实现

    我最近一直在实现递归目录搜索实现 并且使用堆栈来跟踪路径元素 当我使用 string Join 连接路径元素时 我发现它们被颠倒了 当我调试该方法时 我查看了堆栈 发现堆栈内部数组中的元素本身是相反的 即最近 Push 的元素位于内部数组的
  • 在 C 语言中,为什么数组的地址等于它的值?

    在下面的代码中 指针值和指针地址与预期不同 但数组值和地址则不然 怎么会这样 Output my array 0022FF00 my array 0022FF00 pointer to array 0022FF00 pointer to a
  • if constexpr 中的 not-constexpr 变量 – clang 与 GCC

    struct A constexpr operator bool const return true int main auto f auto v if constexpr v A a f a clang 6 接受该代码 GCC 8 拒绝它
  • JavaScript 错误:MVC2 视图中的条件编译已关闭

    我试图在 MVC2 视图页面中单击时调用 JavaScript 函数 a href Select a JavaScript 函数 function SelectBenefit id code alert id alert code 这里 b
  • Unity手游触摸动作不扎实

    我的代码中有一种 错误 我只是找不到它发生的原因以及如何修复它 我是统一的初学者 甚至是统一的手机游戏的初学者 我使用触摸让玩家从一侧移动到另一侧 但问题是我希望玩家在手指从一侧滑动到另一侧时能够平滑移动 但我的代码还会将玩家移动到您点击的
  • 来自嵌入图像的 BitmapSource

    我的目标是在 WPF 窗口上重写 OnRender 方法中绘制图像 someImage png 它是嵌入资源 protected override void OnRender System Windows Media DrawingCont
  • 什么是竞争条件?

    编写多线程应用程序时 最常见的问题之一是竞争条件 我向社区提出的问题是 竞赛条件是什么 你如何检测它们 你如何处理它们 最后 如何防止它们发生 当两个或多个线程可以访问共享数据并且它们试图同时更改它时 就会出现竞争条件 由于线程调度算法可以
  • wordexp 失败时我们需要调用 wordfree 吗?

    wordexp 失败时我们需要调用 wordfree 吗 在某些情况下 调用 wordfree 似乎会出现段错误 例如 当 wordfree 返回字符串为 foo bar 的错误代码时 这在手册页中并不清楚 我已经看到在某些错误情况下使用了
  • 在 azure blob 存储中就地创建 zip 文件

    我将文件存储在 Blob 存储帐户内的一个容器中 我需要在第二个容器中创建一个 zip 文件 其中包含第一个容器中的文件 我有一个使用辅助角色和 DotNetZip 工作的解决方案 但由于 zip 文件的大小最终可能达到 1GB 我担心在进
  • Unity c# 四元数:将 y 轴与 z 轴交换

    我需要旋转一个对象以相对于现实世界进行精确旋转 因此调用Input gyro attitude返回表示设备位置的四元数 另一方面 这迫使我根据这个四元数作为默认旋转来计算每个旋转 将某些对象设置为朝上的简单方法如下 Vector3 up I
  • 让网络摄像头在 OpenCV 中工作

    我正在尝试让我的网络摄像头在 Windows 7 64 位中的 OpenCV 版本 2 2 中捕获视频 但是 我遇到了一些困难 OpenCV 附带的示例二进制文件都无法检测到我的网络摄像头 最近我发现这篇文章表明答案在于重新编译一个文件 o
  • 对于 C# Express 用户来说,有哪些好的工具可以识别可能重复的代码? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 也可以看看 有什么工具可以检查重复的 VB NET 代码吗 https stackoverflow c
  • 如何从 Boost.PropertyTree 复制子树

    我有一些boost property tree ptree 我需要树来删除一些具有特定标签名称的元素 例如 xml 表示源ptree如下
  • 如何在C#中控制datagridview光标移动

    我希望 datagridview 光标向右移动到下一列 而不是在向单元格输入数据后移动到下一行 我试图通过 dataGridView1 KeyDown 事件捕获键来控制光标 但这并不能阻止光标在将数据输入到单元格后移动到下一行 提前感谢你的
  • 如何从 Windows Phone 7 模拟器获取数据

    我有一个 WP7 的单元测试框架 它在手机上运行 结果相当难以阅读 因此我将它们写入 XDocument 我的问题是 如何才能将这个 XML 文件从手机上移到我的桌面上 以便我可以实际分析结果 到目前为止 我所做的是将 Debugger B
  • GCD 与自定义队列

    我想知道这两者的性能有什么区别 dispatch async dispatch get global queue DISPATCH QUEUE PRIORITY HIGH 0 perform complex operation dispat
  • 如何在 ASP.NET Core 中注入泛型的依赖关系

    我有以下存储库类 public class TestRepository Repository
  • 嵌入式linux编写AT命令

    我在向 GSM 模块写入 AT 命令时遇到问题 当我使用 minicom b 115200 D dev ttySP0 term vt100 时它工作完美 但我不知道如何在 C 代码中做同样的事情 我没有收到任何错误 但模块对命令没有反应 有

随机推荐

  • D3 折线图/面积图可以处理无序数据吗?

    请参考以下链接 https bl ocks org mbostock 34f08d5e11952a80609169b7917d4172 这里的数据是有序的 按顺序 如 2000 年 1 月 2000 年 2 月等 但我想让这个 d3 图适用
  • 有没有办法修复错误“不会尝试重新连接。原因:数据库位于不同的区域。”在带有 Firebase 的 Android Studio 中

    当我尝试在我的应用程序中注册时 进度条会无休止地运行 因为我的应用程序无法访问数据库 我尝试了一些获取更新的解决方案googles services json文件并更改我的代码中的 URL 但似乎没有任何效果 出现的错误 W Persist
  • Git 非快进拒绝

    我觉得这个问题已经被问过很多次了 但解决方案通常是 我删除了目录并通过新的签出重新完成了工作 我进行了提交并推送 但意识到我在提交消息中引用了错误的票号 所以我快速查看了一下solution最后在终端中输入以下内容 git reset so
  • 截断的 JTable 打印输出

    我有一个 JTable 它使用 JTextArea 作为其 TableCellRenderer 以便表格单元格可以利用自动换行 JTable 显示正常 当我通过 JTable 将表格打印到打印机时打印方法 输出总是在大约 60 的数据处被截
  • Axes3D 数据标签和绘图限制

    下面是一个小片段 说明了我遇到的与 matplotlib 的 Axes3D 实例中使用的立方体的大小以及轴标签的切断相关的问题 虽然我可以很容易地更改图形画布的背景颜色 但这仍然会导致标签上的文本变形 有谁知道如何最好地更改用于绘制数据的
  • 我无法使用 pack Uri 从 WPF 中的代码访问资源图像文件

    我的应用程序中有一些图像资源 我想以编程方式访问 现在我基于一些源代码 所以我需要通过 Uri 访问 所以我的代码是 new BitmapImage new Uri pack application YearBook component R
  • 使用 for_each 修改 std 容器(即使你不应该这样做)

    我正在参加 C 自学课程 学习标准库的工作原理 我想了解这段代码如何使用for each有效 特别是在突变方面objects 与本机数据类型相对 我意识到你不应该使用for each这边走 但这只是为了学习的目的 我原以为这段代码会改变集合
  • Java 的 SSH 库 [关闭]

    Closed 这个问题不符合堆栈溢出指南 目前不接受答案 有谁有使用 Java 的 SSH 库连接的示例吗 The Java 安全通道 JSCH 是一个非常流行的库 maven ant和eclipse都使用 它是开源的 具有 BSD 风格许
  • Angular Material - MdInput 到 MatInputModule?

    我正在使用什么 Angular 角度材质 2 0 0 beta 12 我在做什么 我刚刚开始一个新项目并安装了材料 从以前的项目复制一些语法时 尝试导入时出现错误 从 angular material 导入 MdInputModule 深入
  • 如何更新另一个更新面板中的控件?

    我在层次结构中有三个更新面板 UpdatePanel1 Root UpdatePanelChild1 UpdatePanelChild2 我可以在 updatePanel2 发生事件时更新 updatePanel1 中的控件吗 我不太喜欢每
  • 如何将数组中的值添加到其前后的值

    我试图将数字数组转换为非零整数元素值的步骤 即 spread 0 0 n 0 0 returns gt 0 n 2 0 n 1 n 0 n 1 0 n 2 spread 0 0 0 n 0 2 returns gt 0 n 3 0 n 2
  • 针对性能不佳的 Lint 警告 - 80+ 次观看

    我收到此 lint 警告错误 highscores xml has more than 80 views bad for performance 这是我的高分表 有 15 行 3 列 这是我的应用程序的 Lite 版本 我的付费版本将容纳
  • 启动错误:java.lang.InknownClassChangeError:org/apache/struts2/convention/DefaultClassFinder$InfoBuildingVisitor

    我有一个 Struts2 应用程序 最初是基于 XML 的 但现在我第一次引入了基于注释的操作 并且该应用程序在启动时崩溃了 鉴于以下操作映射 在应用程序启动时 我收到错误 java lang InstantiationError com
  • python 字典 keyError

    python 新手 看起来像是简单可行的代码片段KeyError patt list jkasb dict for i in patt dict i 1 if dict i is None else dict i 1 This line t
  • 没有 StreamReader 构造函数接受字符串

    我正在将 NET 4 6 1 控制台应用程序移植到 NET Core 我安装了 NETStandard Library 1 6 但它不允许我将文件路径字符串传递到 StreamReader 构造函数中 查看定义确认它不可用 它去哪儿了 这是
  • 在Python中使用静态地址和偏移量从进程读取内存地址

    我正在尝试在 Python 中读取另一个进程的内存 并且我有程序的静态地址和所有偏移量 我正在使用win32api去做这个 我已经可以使用没有偏移量的地址读取进程的内存 但我不知道如何使用偏移量 我已经尝试过该脚本这个答案但它返回 1 我已
  • 使用 python 和 numpy 进行二维卷积

    我正在尝试使用 numpy 在 python 中执行二维卷积 我有一个二维数组 如下所示 内核 H r 代表行 H c 代表列 data np zeros nr nc dtype np float32 fill array with som
  • 如何在foreach迭代中修改多维数组的子元素

    我试图修改多维数组的每个数组元素中第一个子元素的内容 但是 如果我通过引用传递所述元素 则会收到错误消息 不是预期的 我是否需要放弃 foreach arr as list 语法并恢复到标准 for 循环并使用计数器变量进行访问 forea
  • 谷歌街景标题问题

    我正在从事一个项目 我需要显示走向道路的谷歌地图街景 我为全景对象设置了标题 0 但对于不同的位置 它显示的标题不同 例如 在某些情况下 它显示前往街道 而对于某些位置 它显示前往家 panorama theMap getStreetVie
  • 协助UI Dispatcher处理大量的方法调用

    以下帖子已成为bit 比预期更长 我对此表示歉意 但也许你会发现阅读起来很有趣 也许你有一个想法可以帮助我 我正在开发一个小型应用程序 其 GUI 由许多列表控件组成 每个列表控件都有一个thread与之相关的是永久生产正在添加到列表中的字