当您使用a Timer或者Thread只运行程序的整个生命周期时,您是否需要保留对它们的引用以防止它们被垃圾回收?
请放下以下程序可以timer作为类中的静态变量的事实,这只是一个展示问题的玩具示例.
public class Program
{
static void Main(string[] args)
{
CreateTimer();
Console.ReadLine();
}
private static void CreateTimer()
{
var program = new Program();
var timer = new Timer();
timer.Elapsed += program.TimerElapsed;
timer.Interval = 30000;
timer.AutoReset = false;
timer.Enabled = true;
}
private void TimerElapsed(object sender, ElapsedEventArgs e)
{
var timerCast = (Timer)sender;
Console.WriteLine("Timer fired at in thread {0}", GetCurrentThreadId());
timerCast.Enabled = true;
}
~Program()
{
Console.WriteLine("Program Finalized");
}
[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId(); …Run Code Online (Sandbox Code Playgroud) 我真的很挣扎.我正在winformsvisual studio中创建一个应用程序,并且需要一个每半小时打一次的后台计时器 - 这样做的目的是从服务器下载更新.
我尝试了几种不同的方法,但是由于教程/示例不好或者我自己的缺点,它们都失败了C#.我认为到目前为止,向我展示我所尝试过的东西将是浪费时间,因为我认为我的尝试远远不够.
有没有人知道一种清晰简单的方法来实现C#新手很容易理解的异步后台计时器?
前言:我知道如何解决问题.我想知道它为什么会出现.请从上到下阅读问题.
正如我们都应该知道的那样,添加事件处理程序会导致C#中的内存泄漏.请参阅为什么以及如何避免事件处理程序内存泄漏?
另一方面,对象通常具有相似或相关的生命周期,并且不需要取消注册事件处理程序.考虑这个例子:
using System;
public class A
{
private readonly B b;
public A(B b)
{
this.b = b;
b.BEvent += b_BEvent;
}
private void b_BEvent(object sender, EventArgs e)
{
// NoOp
}
public event EventHandler AEvent;
}
public class B
{
private readonly A a;
public B()
{
a = new A(this);
a.AEvent += a_AEvent;
}
private void a_AEvent(object sender, EventArgs e)
{
// NoOp
}
public event EventHandler BEvent;
}
internal class Program …Run Code Online (Sandbox Code Playgroud) 我正在尝试加载间隔进程的队列.换句话说,我有一个队列,我希望队列中的每个项目都在一个单独的时间间隔上运行.
我的问题是,我似乎无法一次运行超过25个线程.我在64位机器上使用.Net 4.5,其默认最大线程数为32768.
如何使我的应用程序运行尽可能多的并发线程,因为我的机器可以处理?
这是一个示例应用程序,它复制了我的生产代码中的实际问题:
class Program
{
static void Main(string[] args)
{
System.Threading.ThreadPool.SetMaxThreads(200, 200);
test t = new test();
t.LoadUrls("http://www.google.com");
while (1 == 1)
{
System.Threading.Thread.Sleep(1000);//refresh every 5 seconds
Console.WriteLine(System.Diagnostics.Process.GetCurrentProcess().Threads.Count);
}
}
public class test
{
public void LoadUrls(string url)
{
for (int i = 0; i < 100; i++)
{
System.Threading.Timer t = new System.Threading.Timer(new System.Threading.TimerCallback(RunInterval), url, 0, 1000);
Console.WriteLine("Loaded {0} feeds.", i);
}
}
private static void RunInterval(object state)
{
string url = state as string;
string …Run Code Online (Sandbox Code Playgroud) System.Timers.Timer如果没有其他对象引用它,是否可以对包含活动Timer()的对象进行垃圾回收?
我的问题很简单,为什么GC无法弄明白该timer对象main应该与timer内部TestTimer和相关的垃圾一起收集EventHandler?
为什么我不断获得console.Writeline输出?
class Program
{
public static void Main()
{
TestTimer timer = new TestTimer();
timer = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Console.ReadKey();
}
}
public class TestTimer
{
private Timer timer;
public TestTimer()
{
timer = new Timer(1000);
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();
}
private void timer_Elapsed(Object sender, ElapsedEventArgs args)
{
Console.Write("\n" + DateTime.Now);
}
}
Run Code Online (Sandbox Code Playgroud) 我偶然发现了一些使用该GC.KeepAlive()方法的代码,我试图了解它是如何工作的.例如,在此代码中:
Timer timer = new System.Timers.Timer(5000);
timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
timer.Enabled = true;
GC.KeepAlive(timer);
Run Code Online (Sandbox Code Playgroud)
在这段代码中,我的理解是创建了一个Timer对象,它产生一个每5秒运行一次的线程.接下来,运行GC线.然后该方法退出,在垃圾收集运行时销毁计时器.
KeepAlive只会在调用KeepAlive之前保持活动状态,它看起来对我来说大概是0.0000001秒并且它不会被破坏,因为它有一个本地引用(除非它正在破坏它,因为没有其他事情发生在计时器对象?)
无论哪种方式,当5000间隔被击中时,该方法将在很久以前结束,并且很可能计时器被破坏.那条线的目的是什么?
可能重复:
定时器,事件和垃圾收集:我错过了什么?
private void TrayForm_Load(object sender, EventArgs e)
{
System.Timers.Timer HideMeTimer = new System.Timers.Timer(2500);
HideMeTimer.Elapsed +=
delegate(object sender2, System.Timers.ElapsedEventArgs e2)
{
this.Invoke(new Action(somestuff));
};
HideMeTimer.Start();
GC.Collect();
}
Run Code Online (Sandbox Code Playgroud)
有人可以告诉我编译器将如何翻译吗?或者很好地解释为什么定时器在加载事件之后继续滴答作响.
(当最后一个引用消失时,不是规则,变量,GC有时会杀死对象!)
让我们说我有一个点击按钮,它执行此操作:
public void ButtonClick(object sender, EventArgs e)
{
System.Timers.Timer NewTimer = new System.Timers.Timer();
NewTimer.AutoReset = false;
NewTimer.Elapsed += new ElapsedEventHandler(TimerElapsed);
NewTimer.Interval = 1000;
NewTimer.Start();
}
public void TimerElapsed(object sender, ElapsedEventArgs e)
{
}
Run Code Online (Sandbox Code Playgroud)
如果单击此按钮100次,那么已创建的实例会发生什么?垃圾收集会启动还是System.Timers.Timer.Close方法需要调用,如果它在哪里,你从哪里调用它?
我在C#.NET 3.5中.看来,通过从同一个线程注册超过10个System.Threading.Timers会导致第一个以某种方式死掉......但不能相信它.如果这是真的,我会感到震惊.
这是我每次收到新消息时启动计时器的行:
System.Threading.Timer tmr = new System.Threading.Timer(WaitAckElapsedTmrHandler, msgId, Constants.TIME_TO_WAIT_FOR_ACK, Timeout.Infinite);
Run Code Online (Sandbox Code Playgroud)
还有什么可能是我的问题?我相信已正确锁定所有线程共享资源,甚至仔细记录锁定区域的所有进出 - >所以我看不到任何死锁.
在这种情况下如何检测死锁?
我有一个每分钟接受 20 个请求的 API,之后我需要等待 1 分钟才能查询它。我有一个项目列表(通常超过 1000 个),我需要从 API 查询其详细信息,我的想法是我可以用来将Partitioner我的列表划分为 20 个项目/请求,但很快我意识到这Partitioner不起作用,我的第二个想法在分区中添加 adelay但这也是一个坏主意,根据我的理解,它会在每个不需要的请求之后添加一个延迟,相反,我需要在每个Partition. 下面是我的代码:
public static async Task<IEnumerable<V>> ForEachAsync<T, V>(this IEnumerable<T> source,
int degreeOfParallelism, Func<T, Task<V>> body, CancellationToken token,
[Optional] int delay)
{
var whenAll = await Task.WhenAll(
from partition in Partitioner.Create(source).GetPartitions(degreeOfParallelism)
select Task.Run(async delegate {
var allResponses = new List<V>();
using (partition)
while (partition.MoveNext())
{
allResponses.Add(await body(partition.Current));
await Task.Delay(TimeSpan.FromSeconds(delay));
}
return allResponses;
}, token));
return whenAll.SelectMany(x => x);
}
Run Code Online (Sandbox Code Playgroud)
有谁知道我怎样才能做到这一点?
c# ×11
timer ×6
.net ×2
asynchronous ×1
capture ×1
events ×1
memory-leaks ×1
performance ×1
winforms ×1