- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个 c# 控制台,我已将其制作成 Windows 服务,我希望它能够可靠且持续地运行。
它有几个方面。每个都非常定期地运行。我以前读过 TaskScheduler vs Windows Service 运行这种东西,并选择了这种方法,因为有些东西几乎一直在运行。
我正在使用计时器回调,每个都有自己的回调,类似于这个简化版本:
class Program
{
static PollingService _service;
static void Main()
{
_service = new PollingService();
TimerCallback tc1 = _service.TaskType1;
TimerCallback tc2 = _service.TaskType2;
TimerCallback tc3 = _service.TaskType3A;
TimerCallback tc4 = _service.TaskType3B;
Timer t1 = new Timer(tc1, null, 1000, 5000);
Timer t2 = new Timer(tc2, null, 2000, 8000);
Timer t3 = new Timer(tc3, null, 3000, 11000);
Timer t4 = new Timer(tc4, null, 4000, 13000);
Console.WriteLine("Press Q to quit");
while (Console.ReadKey(true).KeyChar != 'q')
{
}
}
}
class PollingService
{
public void TaskType1(object state)
{
for (int i = 1; i <= 10; i++)
{
Console.WriteLine($"TaskOne numbering {i}");
Thread.Sleep(100);
}
}
public void TaskType2(object state)
{
for (int i = 10; i <= 100; i++)
{
Console.WriteLine($"TaskTwo numbering {i}");
Thread.Sleep(100);
}
}
public void TaskType3A(object state)
{
Increment(200000000);
}
public void TaskType3B(object state)
{
Increment(40000);
}
private void Increment(int startNumber)
{
for (int i = startNumber; i <= startNumber + 1000; i++)
{
Console.WriteLine($"Private {startNumber} numbering {i}");
Thread.Sleep(5);
}
}
}
1 首先,我想确保当一个人有时运行很长时间时,它们不会相互捆绑。
例如。如果有时任务 1 需要 20 秒才能运行,我想在前一个可能仍在运行时防止重复计时器,事实上所有计时器都一样。例如。如果 t2 运行的时间比平常长一点,那么不要启动另一个。我读过一些关于 if (Monitor.TryEnter(lockObject))
的内容,这是处理该要求的最佳方式吗?
2 其次,如果他们都访问相同的资源(在我的例子中是 EF 上下文),这样 t3 已经在使用它,并且 t4 试图这样做。有没有办法让计时器等到另一个完成?
3 最后,有什么方法可以监控这些计时器/回调吗?当我将它作为 Windows 服务运行时,我想提供一个 UI 来查看它的状态。我的最终目标是提供一个 UI,用户可以看到任务是否正在运行,如果没有,则在一段时间内未设置为运行时按需触发它。但同时,不要在运行时创建副本。
我想知道我是否应该将这些作为单独的问题提出,但它们似乎与彼此的决定交织在一起。
最佳答案
如果你必须确保每个线程没有任何重叠,你可以使用 Timer.Change(int, int)
方法在回调开始时停止执行,然后在回调结束时恢复。您还可以为每个线程使用 ManualResetEvent
来施展魔法,但这会变得困惑。
我不喜欢用于线程的计时器,因此尽可能避免使用它们。如果您可以牺牲“每个线程必须在n 秒后运行”,那就去做吧。改用带有取消标记的任务,它将解决您的重叠问题。例如:
A.
public class Foo
{
private CancellationTokenSource _cts;
//In case you care about what tasks you have.
private List< Task > _tasks;
public Foo()
{
this._cts = new CancellationTokenSource();
this._tasks.Add(Task.Factory.StartNew(this.Method1, this._cts.Token));
this._tasks.Add(Task.Factory.StartNew(this.Method2, this._cts.Token));
this._tasks.Add(Task.Factory.StartNew(this.Method3, this._cts.Token));
this._tasks.Add(Task.Factory.StartNew(this.Method4, this._cts.Token));
}
private void Method1(object state)
{
var token = (CancellationToken) state;
while ( !token.IsCancellationRequested )
{
//do stuff
}
}
private void Method2(object state)
{
var token = (CancellationToken)state;
while (!token.IsCancellationRequested)
{
//do stuff
}
}
private void Method3(object state)
{
var token = (CancellationToken)state;
while (!token.IsCancellationRequested)
{
//do stuff
}
}
private void Method4(object state)
{
var token = (CancellationToken)state;
while (!token.IsCancellationRequested)
{
//do stuff
}
}
public void StopExecution()
{
this._cts.Cancel();
}
}
如果一次被多个线程使用,一个 EF 上下文将抛出异常。有一种方法可以使用 lock
来同步它。根据上面的示例,它看起来像这样:
B.
public class Foo
{
private object _efLock;
public Foo()
{
this._efLock = new object();
}
.
.
.
private void MethodX(object state)
{
var token = (CancellationToken)state;
while (!token.IsCancellationRequested)
{
lock(this._efLock)
{
using(.......
}
}
}
}
您必须在访问 EF 上下文的每个线程中执行此操作。请记住,由于复杂的 lock
场景会带来认知负担,维护工作会再次变得烦人。
我最近开发了一个应用程序,其中我需要多个线程来访问同一个 EF 上下文。正如我上面提到的,锁定太多(并且有性能要求),所以我设计了一个解决方案,每个线程将其对象添加到一个公共(public)队列,而一个单独的线程除了从队列中提取数据外什么都不做调用 EF。这样,EF 上下文只能由一个线程访问。问题解决了。给定上面的示例,这看起来像这样:
C.
public class Foo
{
private struct InternalEFData
{
public int SomeProperty;
}
private CancellationTokenSource _dataCreatorCts;
private CancellationTokenSource _efCts;
//In case you care about what tasks you have.
private List< Task > _tasks;
private Task _entityFrameworkTask;
private ConcurrentBag< InternalEFData > _efData;
public Foo()
{
this._efData = new ConcurrentBag< InternalEFData >();
this._dataCreatorCts = new CancellationTokenSource();
this._efCts = new CancellationTokenSource();
this._entityFrameworkTask = Task.Factory.StartNew(this.ProcessEFData, this._efCts.Token);
this._tasks.Add(Task.Factory.StartNew(this.Method1, this._dataCreatorCts.Token));
this._tasks.Add(Task.Factory.StartNew(this.Method2, this._dataCreatorCts.Token));
.
.
.
}
private void ProcessEFData(object state)
{
var token = (CancellationToken) state;
while ( !token.IsCancellationRequested )
{
InternalEFData item;
if (this._efData.TryTake(out item))
{
using ( var efContext = new MyDbContext() )
{
//Do processing.
}
}
}
}
private void Method1(object state)
{
var token = (CancellationToken) state;
while ( !token.IsCancellationRequested )
{
//Get data from whatever source
this._efData.Add(new InternalEFData());
}
}
private void Method2(object state)
{
var token = (CancellationToken) state;
while ( !token.IsCancellationRequested )
{
//Get data from whatever source
this._efData.Add(new InternalEFData());
}
}
public void StopExecution()
{
this._dataCreatorCts.Cancel();
this._efCts.Cancel();
}
}
当谈到从执行线程读取数据时,我通常使用 SynchronizationContext
。我不知道它是否适合使用,其他人可能会对此发表评论。创建一个 Synchronization 对象,将其传递给您的线程并让它们使用必要的数据对其进行更新并将其发布到您的 UI/控制台线程:
D.
public struct SyncObject
{
public int SomeField;
}
public delegate void SyncHandler(SyncObject s);
public class Synchronizer
{
public event SyncHandler OnSynchronization;
private SynchronizationContext _context;
public Synchronizer()
{
this._context = new SynchronizationContext();
}
public void PostUpdate(SyncObject o)
{
var handleNullRefs = this.OnSynchronization;
if ( handleNullRefs != null )
{
this._context.Post(state => handleNullRefs((SyncObject)state), o);
}
}
}
public class Foo
{
private Synchronizer _sync;
public Foo(Synchronizer s)
{
this._sync = s;
}
private void Method1(object state)
{
var token = (CancellationToken) state;
while ( !token.IsCancellationRequested )
{
//do things
this._sync.PostUpdate(new SyncObject());
}
}
}
再一次,我就是这样做的,我不知道这是否是正确的方法。
关于c# - 多个计时器/回调——防止重复和监控它们的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35272914/
我想知道如何考虑需要您做出某些选择才能看到最终结果的搜索系统。我说的是 select 表单,您可以在其中根据您的选择继续操作,然后您会看到结果。 下面描述了我正在谈论的一个随机示例。想象一下 Init
您好,我目前正在编写一些软件来管理我们的库存。我搜索了 2 个表 master_stock(保存每一个股票代码和描述)库存(保存库存代码、地点、数量...) 一切都很好,但这是我遇到的问题。 假设我的
我有 2 个表,我想合并其数据。id 是我的关键字段(增量且不同)。表1和表2字段说明例如:id - 名称 - 值 我想将表2的所有数据插入表1,它们有不同的数据,但在某些行中有相同的id。 所以当我
我正在努力解决汇编中的一个问题,我必须获取十六进制代码的第一个字节 (FF) 并将其复制到整个值中: 0x045893FF input 0xFFFFFFFF output 我所做的
我有 Eclipse Indigo 版本,我可以在其中运行 Java 和 C++ 项目。 但我只想使用另一个 Eclipse 来编写 C++ 项目。所以我将 eclipse(不是工作区)的源文件夹复制
This question already has answers here: What is a NullPointerException, and how do I fix it? (12个答案)
This question already has answers here: Numbering rows within groups in a data frame (8个答案) 5个月前关闭。
我知道用q记录到寄存器中,但我想知道是否可以设置一些东西来快速调用最后一个记录,就像一样。 回顾最后一个简短的编辑命令(有关 的讨论请参阅 here。)。 我知道@@,但它似乎只有在执行@z之后才起作
来自 Eclipse 并且一直习惯于复制行,发现 Xcode 没有这样的功能是很奇怪的。或者是吗? 我知道可以更改系统范围的键绑定(bind),但这不是我想要的。 最佳答案 要删除一行:Ctrl-A
假设我有一个包含元素的列表,例如[1,2,3,4,5,6,7,8]。我想创建长度为 N 的该元素的所有排列。 因此,对于N = 4,它将是[[1,1,1,1],[1,1,1,2],[1,1,2,1],
我有一个带有 JMenu 的 JFrame。当我在某些情况下添加包含图像的 JPanel 时,程序首次启动时菜单会重复。调整大小时重复的菜单消失。任何建议都非常感激。谢谢。代码如下: public c
我正在尝试查找目录中文件的重复项。 我对这个 block 有一个问题,它以文件地址作为参数: public void findFiles(ArrayList list){ HashMap hm
我知道这个问题已经发布并且已经给出了答案,但我的情况不同,因为我在单个方法上填充多个下拉列表,所以如果我点击此链接 After every postback dropdownlist items re
我正在尝试为我的日历应用程序实现重复模式。我希望它的工作方式与 Outlook 在您设置重复约会时的工作方式相同。 public async Task> ApplyReccurrencePeriod
我有一个利用 cookie 来支持准向导的应用程序(即,它是一组相互导航的页面,它们必须以特定顺序出现以进行注册)。 加载 Logon.aspx 页面时 - 默认页面 - 浏览器 cookie 看起来
我有 3 个输入,代码检查它们是否为空,如果为空,则将变量值添加到输入中。 所以我有 3 个具有值的变量: var input1text = "something here"; var input2t
根据数组的长度更改数组的每个元素的最佳方法是什么? 例如: User #1 input = "XYZVC" Expected Output = "BLABL" User #2 input = "XYZ
我在让 Algolia 正常工作时遇到了一些麻烦。我正在使用 NodeJS 并尝试在我的数据库和 Algolia 之间进行一些同步,但由于某种原因似乎随机弹出大量重复项。 如您所见,在某些情况下,会弹
遵循以下规则: expr: '(' expr ')' #exprExpr | expr ( AND expr )+ #exprAnd | expr ( OR expr )+ #exprO
我有一个布局,我想从左边进入并停留几秒钟,然后我希望它从右边离开。为此,我编写了以下代码: 这里我在布局中设置数据: private void loadDoctor(int doctorsInTheL
我是一名优秀的程序员,十分优秀!