0

我会尽量让这个问题变得简单,这样就可以很容易地了解这个场景。我正在尝试为学校项目构建一个与股票相关的应用程序,该应用程序正在从网络上获取特定股票的数据。因此,用户在文本框中输入股票名称,单击按钮后,股票名称将传递给下载该特定股票数据的方法。现在我希望每秒为同一股票调用该方法,以便用户可以获得最新更新。到现在都没有问题。但是当用户想要监控不止一只股票时,我需要深入研究线程。对于每只股票,每秒都会有一个线程调用更新股票方法。例如,有 5 只股票,所以应该有 5 个线程同时工作,每秒调用该方法来更新结果。

为此,我在按钮单击事件中使用 System.Threading.Timer,它正在调用库存更新方法。但问题是,当我输入第一只股票时,该方法只被调用了 2 次,第二只股票被调用了 6 次,第三只股票被调用了 12 次以上。这种奇怪行为背后的原因是什么。

任何想法是否有任何其他方法可以实现我想要做的事情。以下是我正在处理的代码。

private void button1_Click(object sender, EventArgs e)
{
    dataGridView1.Rows.Add("","","","","","test", "test");
    int i= dataGridView1.Rows.Count - 1;
    string stock = textBox1.Text + ":"+i;

    System.Threading.Timer tmr = new System.Threading.Timer(Tick,stock,1000,2000);
}

public void Tick(object stock)
{
    lock (locker)
    {
        string maindata = stock.ToString();
        string[] testing = maindata.Split(':');
        byte[] data = null;
        Uri uri = new Uri("some url where i am getting data from");
        WebClient wc = new WebClient();

        wc.DownloadDataCompleted += delegate(object sender, DownloadDataCompletedEventArgs e)
        {
            data = e.Result;
        };
        wc.DownloadDataAsync(uri);
        while (wc.IsBusy)
        {
            Thread.Sleep(100);
        }
        string strData = Encoding.ASCII.GetString(data);
        string[] s = strData.Split('{');
        string data1 = s[4];
        string[] data2 = data1.Split('}');
        string final = "[{" + data2[0] + "}]";

        Form1 obj = new Form1();
        List<Form1> jarray = JsonConvert.DeserializeObject<List<Form1>>(final);

        dataGridView1.Rows[System.Convert.ToInt32(testing[1]) - 1].Cells[0].Value = jarray[0].Symbol;
        dataGridView1.Rows[System.Convert.ToInt32(testing[1]) - 1].Cells[1].Value = jarray[0].Ask;
        dataGridView1.Rows[System.Convert.ToInt32(testing[1]) - 1].Cells[2].Value = jarray[0].Volume;
        dataGridView1.Rows[System.Convert.ToInt32(testing[1]) - 1].Cells[3].Value = jarray[0].Bid;
    }      
}
4

4 回答 4

1

Since with every click you are creating a new Timer. This will mean with every subsequent click, more timers will respond so you start getting the events twice, 4 times, ....

Move this line out of click and put it in the initialization of the form:

System.Threading.Timer tmr = new System.Threading.Timer(Tick,stock,1000,2000);

This does not mean I fully approve your approach since that has nothing to do with the question you are asking.

于 2011-04-04T16:26:51.363 回答
1

我建议您查看使用委托的异步编程。在每个滴答声(仅使用 1 个计时器)上,您应该异步启动一个委托,以获取用户请求的每只股票的值。

于 2011-04-04T18:14:37.457 回答
0

@Prashant - 显然你的方法不正确。您真正想要发生的是拥有多个线程,这些线程将以不同的时间间隔滴答作响。正如 Aliostad 暗示的那样,您的方法不正确。

System.Threading.Timer 是一个简单的轻量级计时器,它使用回调方法并由线程池线程提供服务。不建议与 Windows 窗体一起使用,因为它的回调不会发生在用户界面线程上。System.Windows.Forms.Timer 是与 Windows 窗体一起使用的更好选择。对于基于服务器的计时器功能,您可以考虑使用 System.Timers.Timer,它会引发事件并具有附加功能。

我要做的是使用互斥锁方法来确定是否需要新线程。我会传递股票的名称并在线程本身内启动计时器。如果你想要一个功能来“暂停”或“停止”一只股票被观看就很容易了。

您使用的当前类是线程化的,您的方法本身是有缺陷的。

As for each stock there will be a thread will be calling the update stock method every second. So for example there are 5 stocks so there should be 5 threads that are working simultaneously calling the method every second to update the results. I hope i have made the problem clear to understand.
  • 除了这不是你在做什么。您实际上正在做的是在每次按下按钮时(对于每只股票)启动一个新的计时器线程,这当然不是您真正想要做的(基于您自己的陈述)。
于 2011-04-04T17:14:31.450 回答
0

“但是当用户想要监控不止一只股票时,我需要深入研究线程”。不对。现在我不想破坏一个很好的机会,一头扎进线程,但你不需要在这里。为什么不同时刷新所有股票呢?

因此,每次计时器滴答作响时,您都可以一次性下载所有股票的价格。如果您可以控制服务器端接口(从中获取数据),请创建一个接受股票代码集合并返回股票价格集合的方法。如果服务器一次只返回一个,您可以在循环中让它们一个接一个。

此外,当您真的想要快速响应的东西时,不要每秒轮询新价格,而是让服务器通过订阅事件等方式在发生变化时通知您。一些股票几分钟内不会移动,而另一些则移动得非常快。对于大多数交易目的而言,一整秒就是一生。如果您使用的是 WPF,请查看 DataBinding 和 INotifyPropertyChanged。这非常适合这类问题。

GJ

于 2011-04-04T18:35:05.610 回答