C# - 多线程,一个线程运行无限循环
我是多线程新手(并且是一个初学者/中级程序员),所以我可能会遗漏一些非常明显的东西。我目前正在开发一个应用程序,该应用程序必须从服务器(确切地说是彭博服务器)提取数据并运行业务逻辑。
要从服务器上获取数据,您基本上必须运行无限循环来不断刷新数据。目前,所有数据拉取代码/逻辑都位于一个单独的类中,并且具有许多使用最新数据进行更新的公共对象(下面代码中的 dataDict)。
我的想法是在单独的线程上运行程序的数据拉取部分,并让其余的业务逻辑在主线程上运行。然后,每当业务逻辑需要最新数据时,它就可以从另一个线程(字典)调用数据对象。关于下面的代码,我希望该类在后台运行,并让主要业务逻辑选取 Dictionary、Object> 。需要时使用 dataDict。我真的不知道如何最好地做到这一点。
我尝试使用BackgroundWorker,但遇到的问题是,由于循环是无限的,我永远无法触发RunWorkerCompleted事件处理程序,并且DoWork处理程序将被调用得太快(数据完全下载需要一些时间) 。
任何帮助将不胜感激!
为了说明程序的一部分,数据拉取的代码是(注意,我必须进行一些编辑,因此大括号/方括号可能不完美):
class BloombergSync
{
private Session mainSession = new Session();
private List<String> contracts = new List<string>();
private List<String> fields = new List<string>();
public List<String> safeContracts = new List<string>();
public List<String> safeFields = new List<string>();
public Dictionary<Tuple<string, string>, Object> dataDict = new Dictionary<Tuple<string, string>, object>();
private BackgroundWorker worker = new BackgroundWorker();
{
while (true)
{
try
{
Event eventObj = mainSession.NextEvent();
foreach (Message msg in eventObj.GetMessages())
{
if (eventObj.Type == Event.EventType.SUBSCRIPTION_DATA)
{
Element dataElement = msg.AsElement;
//Figures out which contract the data is in reference to.
string topic = msg.TopicName;
// Then must add the data to the appropriate contract and field.
foreach (string field in fields)
{
if (dataElement.HasElement(field, true))
{
// Collects data for the field
Element elm = dataElement.GetElement(field);
var dataPoint = elm.GetValue();
// Have to figure out how to select first topic, and then the field within that topic. Has
// two keys (first topic, then field).
Tuple<string, string> tuple = new Tuple<string, string>(topic, field);
dataDict[tuple] = dataPoint;
worker.ReportProgress(1);
}
}
}
else
{
//Do Nothing if not data
}
}
}
catch (Exception ex)
{
System.Console.WriteLine("Got Exception:" + ex);
}
}
}
I'm new to multithreading (and a somewhat beginner / intermediate programmer), and so I may be missing something very obvious. I'm currently working on an application that has to pull data off a server (a bloomberg server to be exact) and also run business logic.
To pull data off the server, you basically have to run an endless loop to constantly refresh the data. Currently, all the data pull code / logic is in one seperate class, and has a number of public objects (dataDict in code below) that get updated with the newest data.
My thought was to run the data pull part of the program on a seperate thread, and have the rest of the business logic run on the main thread. Then, whenever the business logic required the most recent data, it could just call the data object from the other thread (a dictionary). In regards to the code below, I would like that class to run in the background and have the main business logic pick up the Dictionary, Object> dataDict when required. I'm really not sure how to best do this though.
I tried using a BackgroundWorker, but the issue that I ran into was that because the loop was endless I could never fire the RunWorkerCompleted event handler, and the DoWork handler would be called too soon (it takes some time for the data to fully download).
Any help would be much appreciated!!
To illustrate part of the program, the code for the datapull is (note, I had to do some editing so the braces/brackets may not be perfect):
class BloombergSync
{
private Session mainSession = new Session();
private List<String> contracts = new List<string>();
private List<String> fields = new List<string>();
public List<String> safeContracts = new List<string>();
public List<String> safeFields = new List<string>();
public Dictionary<Tuple<string, string>, Object> dataDict = new Dictionary<Tuple<string, string>, object>();
private BackgroundWorker worker = new BackgroundWorker();
{
while (true)
{
try
{
Event eventObj = mainSession.NextEvent();
foreach (Message msg in eventObj.GetMessages())
{
if (eventObj.Type == Event.EventType.SUBSCRIPTION_DATA)
{
Element dataElement = msg.AsElement;
//Figures out which contract the data is in reference to.
string topic = msg.TopicName;
// Then must add the data to the appropriate contract and field.
foreach (string field in fields)
{
if (dataElement.HasElement(field, true))
{
// Collects data for the field
Element elm = dataElement.GetElement(field);
var dataPoint = elm.GetValue();
// Have to figure out how to select first topic, and then the field within that topic. Has
// two keys (first topic, then field).
Tuple<string, string> tuple = new Tuple<string, string>(topic, field);
dataDict[tuple] = dataPoint;
worker.ReportProgress(1);
}
}
}
else
{
//Do Nothing if not data
}
}
}
catch (Exception ex)
{
System.Console.WriteLine("Got Exception:" + ex);
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
听起来像是一个生产者-消费者场景。您需要一个
线程安全
对象(在您的例子中是一个队列)来传输数据。在 .NET 4.0 中,有一个
System.Collections.Concurrent
,它是线程安全的
,您可以在项目中使用。然后,后台工作人员可以将数据放入CuncurrentQueue
中,并且消费者可以将数据项出队。Sounds like a
producer-consumer
scenario. You need athread-safe
object (in your case a queue) for transferring data.In
.NET 4.0
there's aSystem.Collections.Concurrent
which isthread-safe
and you can use in your project. Then you background worker can put data inCuncurrentQueue
and consumer(s) can dequeue data items.