我正在尝试使用Timer
来触发事件以通过网络发送数据。我创建了一个简单的类来进行调试。基本上我有List<string>
我想发送。我想要发生以下事情:
List
Timer
10秒List
Timer.Elapsed
Timer
。到目前为止,我有这个:
public static List<string> list;
public static Timer timer;
public static bool isWiredUp = false;
public static void Log(string value) {
if (list == null) list = new List<string>();
list.Add(value);
//this does not reset the timer, elapsed still happens 10s after #1
if (timer != null) {
timer = null;
}
timer = new Timer(10000);
timer.Start();
timer.Enabled = true;
timer.AutoReset = false;
if (!isWiredUp) {
timer.Elapsed += new ElapsedEventHandler(SendToServer);
isWiredUp = true;
}
}
static void SendToServer(object sender, ElapsedEventArgs e) {
timer.Enabled = false;
timer.Stop();
}
有什么想法吗?
答案 0 :(得分:11)
您可以使用Stop
函数,紧接着Start
函数来“重启”计时器。使用它可以在首次创建类时创建Timer
,在此时连接Elapsed事件,然后在添加项目时调用这两种方法。它将启动或重新启动计时器。请注意,在尚未启动的计时器上调用Stop
不执行任何操作,它不会引发异常或导致任何其他问题。
public class Foo
{
public static List<string> list;
public static Timer timer;
static Foo()
{
list = new List<string>();
timer = new Timer(10000);
timer.Enabled = true;
timer.AutoReset = false;
timer.Elapsed += SendToServer;
}
public static void Log(string value)
{
list.Add(value);
timer.Stop();
timer.Start();
}
static void SendToServer(object sender, ElapsedEventArgs e)
{
//TODO send data to server
//AutoReset is false, so neither of these are needed
//timer.Enabled = false;
//timer.Stop();
}
}
请注意,您可能不希望使用List
,而是使用BlockingCollection<string>
。这有几个优点。首先,如果从多个线程同时调用,Log
方法将起作用;因为多个并发日志可能会破坏列表。这也意味着SendToServer
可以在添加新项目的同时将项目从队列中取出。如果您使用List
,则需要lock
对列表的所有访问权限(这可能不是问题,但不是那么简单)。
答案 1 :(得分:0)
使用IObservable(Rx)很容易实现这种功能。
让我们通过声明Subject<string>
作为您的列表来使用.OnNext来简化问题。一旦你有了一个可观察的主题,你就可以通过单一的行来做你想做的事情。 System.Reactive.Linq。这在下面的伪c#
subject
.Buffer(<your timespan>,1) //buffer until either a value is added or the timeout expires
.Subscribe(x =>
{
if (x.Count == 0) //the timeout expired so send on
{
SendAccumulatedListToServer(<your list>);
<clear your list>
}
else
{
<your list>.Add(x);
}
});
答案 2 :(得分:-4)
你正在实施的是完全错误的做法。看看消费者生产者模型:
http://msdn.microsoft.com/en-us/library/hh228601.aspx
您要做的事情通常被称为消费者/生产者数据流模型。基本上你有一些东西生成一个要在某处发送的数据列表,而不是每次将一个项目添加到你希望在组中发送它们的列表时发送它。所以你有一个生产者(代码将数据发送到被发送)和消费者(发送数据的代码)。
通常这个问题是通过生成一个监视列表的线程(通常是队列)并定期发送数据来解决的,最好的方法是使用EventWaitHandle。
以下是一些非常简化的代码示例
class ServerStuff
{
public void Init()
{
datatosend = new List<string>();
exitrequest = new EventWaitHandle(false, EventResetMode.ManualReset); //This wait handle will signal the consumer thread to exit
Thread t = new Thread(new ThreadStart(_RunThread));
t.Start(); // Start the consumer thread...
}
public void Stop()
{
exitrequest.Set();
}
List<string> datatosend;
EventWaitHandle exitrequest;
public void AddItem(string item)
{
lock (((ICollection)datatosend).SyncRoot)
datatosend.Add(item);
}
private void RunThread()
{
while (exitrequest.WaitOne(10 * 1000)) //wait 10 seconds between sending data, or wake up immediatly to exit request
{
string[] tosend;
lock (((ICollection)datatosend).SyncRoot)
{
tosend = datatosend.ToArray();
datatosend.Clear();
}
//Send the data to Sever here...
}
}
}