【问题标题】:How can you run different periodic tasks with timers with different intervals?如何使用具有不同间隔的计时器运行不同的周期性任务?
【发布时间】:2015-06-17 02:49:48
【问题描述】:

我确定这个问题已经在某个地方得到了回答,但是几个小时以来我一直在尝试在这里找到一种方法,除了跨过Thread Timers(这对于周期性事件来说很好,但当计时器有不同的变量和间隔使用)我没有找到任何东西。我真的不确定要搜索什么。非常感谢更好的线程标题或描述!

Thread 中,我正在下载一个 JSON,其中包含有关虚拟物品的信息,然后使用HTTPClient 解析这些值并将其添加到 ListView 中。每个项目的 JSON 看起来像这样(项目名称从 TextBox 中读取并添加到请求和 ListView)

{  
   "success":true,
   "price":"31,98",
   "amount":"33"
}

ListView 包含 4 列,而在 Interval 列中输入所需的刷新间隔。

Item Name    Price    Amount    Interval

我的计划:我想用普通的文本框和按钮将项目名称和间隔添加到 ListView。然后我想启动计时器,其中每个都将读出一个项目的间隔,然后用列表中存放的间隔刷新相应项目的价格。每个项目都应该有一个 Timer,可以独立于其他 Timer 执行 HTTP 请求。

线程一次只处理一个项目,但它不会定期自动刷新值;

private void getPrice()
        {
            try
            {
                    HttpClient client = new HttpClient();

                    JObject o = JObject.Parse(client.GetStringAsync("http://localhost/item.php?itemname=" + tb_MarketName.Text).Result);

                    string Price = (string)o["price"];
                    string Amount = (string)o["amount"];

                    lV_Items.Invoke((Action)delegate
                    {

                        ListViewItem items = new ListViewItem(tb_ItemName.Text));

                        items.SubItems.Add(Price);
                        items.SubItems.Add(Amount);
                        items.SubItems.Add(tb_Interval.Text);

                        lV_Items.Items.Add(items);
                });
            }
            catch (Exception e)
            {
                SendMail("Crash at " + DateTime.Now.ToString(), e.ToString());
            }
        }

【问题讨论】:

    标签: c# multithreading timer task


    【解决方案1】:

    如果有一个计时器呢?使用AutoReset = true; 将其间隔设置为列表中可用的最低间隔(本例中假设为1 分钟)。在Elapsed 事件中,浏览您的列表并确定哪些项目适合在当前时间更新(基于它们的间隔和它们的最后更新时间与当前时间),并将它们添加到IEnumerable 集合。因此,在 12:00 PM 最后一次更新的订单项,间隔为 5 分钟,此时计时器在 12:05 PM 触发。

    在您的收藏中拥有您的项目后,您可以在收藏中运行Parallel.Foreach(),在里面调用您的getPrice() 代码。这实际上将多线程您的更新,而不会添加所有Timers 的混乱。如果您将 getPrice() 更改为异步方法,您可以通过事件阻止长时间运行的更新(例如下午 12:07)阻止下一次更新(下午 12:08)。

    【讨论】:

    • 根据您使用的 Timer 类,使用多个计时器会限制您的可伸缩性。正如@chris 指出的那样,任务生产者/消费者中的单个计时器非常有用
    【解决方案2】:

    尝试使用 Microsoft 的响应式框架 (NuGet "Rx-Main")。

    这将是您的全部代码:

    var subscription =
        lV_Items.ToObservable()
            .SelectMany(x =>
                Observable
                    .Interval(TimeSpan.FromSeconds(x.Interval))
                    .SelectMany(n =>
                        Observable
                            .Using(
                                () => new System.Net.Http.HttpClient(),
                                client => Observable.FromAsync(
                                    () => client.GetStringAsync("http://localhost/item.php?itemname=" + x.MarketName)))
                            .Select(x => JObject.Parse(x))
                            .Select(o => new { lv_item = x, price = (string)o["price"], amount = (string)o["amount"] })))
            .ObserveOn(lV_Items)
            .Subscribe(result =>
            {
                result.lv_item.Amount = result.amount;
                result.lv_item.Price = result.price;
            });
    

    要关闭这一切,您只需致电subscription.Dispose();

    你必须让列表视图代码正常工作,因为我刚刚做了一个快速的拼凑来告诉你该怎么做。

    【讨论】:

      猜你喜欢
      • 2015-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-09
      • 2015-04-24
      • 2013-05-31
      • 2017-05-21
      • 1970-01-01
      相关资源
      最近更新 更多