如何使用不同间隔的计时器运行不同的周期性任务?

时间:2015-06-17 02:49:49

标签: c# multithreading timer task

我确定这个问题已经在某个地方得到了解答,但是我试图在这里找到一个方法,因为几个小时后再踩到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,它可以独立于其他定时器执行HTTP请求。

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

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

2 个答案:

答案 0 :(得分:2)

拥有一个计时器怎么样?使用AutoReset = true;将其间隔设置为列表中可用的最低可能间隔(假设此示例为1分钟)。在Elapsed事件中,浏览您的列表并确定哪些项目适合在当前时间更新(根据其间隔和上次更新时间与当前时间),并将其添加到{{1}收集。因此,当计时器在下午12:05点火时,最后一次更新时间为中午12点,间隔为5分钟的订单项。

在您的收藏中有物品后,您可以在收集的IEnumerable内部调用Parallel.Foreach()代码。这将基本上多线程化您的更新,而不会添加所有getPrice()的混乱。如果将Timers更改为异步方法,则可以阻止长时间运行的更新(例如下午12:07)阻止下一个更新(下午12:08)。

答案 1 :(得分:1)

尝试使用Microsoft的Reactive Framework(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();

您必须让列表视图代码正常工作,因为我刚刚做了一个快速的工具来向您展示该做什么。