我正在创建一个仅在概念验证阶段的小型控制台应用程序。我们的想法是,它将查询第三方API的最终事件。 (那部分工作得很好)。
当一个事件到来时,我们需要将该事件的json字符串粘贴到我们这边的sqlite数据库中。同时,我需要一个在同一个应用程序中运行的进程,该进程在sqlite表中不断查找记录,当它找到一个时,它会处理它。
这是我到目前为止所拥有的......(同样,这只是一个概念证明,同时我学习了如何设置它的基础知识)......
static void Main(string[] args)
{
var t = CheckEventsAsync();
while (true)
{
System.Threading.Thread.Sleep(5000);
DataAccess.InsertData("INSERT INTO events(value) VALUES ('this is an event');");
}
}
static private async Task CheckEventsAsync()
{
DataTable dt = await DataAccess.LoadDataAsync("SELECT * FROM events");
foreach (var dr in dt.Rows)
{
Console.WriteLine("got an event!");
}
}
问题是CheckEventsAsync()只触发一次,然后当5秒计时器关闭时,一条记录被添加到表中,没有任何反应。
我是否需要使用EventHandler(使用委托等)来完成这项工作?或者可能不这样做吗?
谢谢!
哦,差点忘了......(这是因为如果有数据则返回数据表,如果没有则返回null。但我不确定我是否正确地为整体目标做准备)...
public static async Task<DataTable> LoadDataAsync(string txtQuery)
{
var dataTable = new DataTable();
var connection = new SQLiteConnection(_source);
using (connection)
{
connection.Open();
var command = connection.CreateCommand();
command.CommandText = txtQuery;
var task = await command.ExecuteReaderAsync();
dataTable = new DataTable();
dataTable.Load(task);
connection.Close();
}
if (dataTable != null & dataTable.Rows.Count > 0)
return dataTable;
else
return null;
}
修改
到目前为止,我从答案中看到,我在提问时做得不好。我需要运行两个进程:
While(true)
循环内不会有计时器。它将是一个WebSocket侦听器。 两者需要在同一个应用程序中运行,但彼此独立。
我希望我有意义吗?
答案 0 :(得分:4)
使用Microsoft的Reactive Framework:
static readonly BlockingCollection<ItemToProcess> _queue = new BlockingCollection<ItemToProcess>(new ConcurrentQueue<ItemToProcess>());
static void Main(string[] args)
{
IDisposable inserts =
Observable
.Interval(TimeSpan.FromSeconds(5.0))
.Subscribe(_ =>
{
_queue.Add(new ItemToProcess() { Value = "value" });
});
IDisposable checks =
new CompositeDisposable(
Disposable.Create(() => _queue.CompleteAdding()),
_queue
.GetConsumingEnumerable()
.ToObservable(Scheduler.Default)
.Subscribe(item =>
{
Console.WriteLine(item.Value);
}));
}
这可以处理所有线程,并可以轻松关闭应用程序。只需在退出前致电inserts.Dispose()
和checks.Dispose()
。
NuGet“System.Reactive”获取位。
答案 1 :(得分:3)
由于所有操作都在同一个操作系统进程中运行 - 您不需要不断地为新事件轮询数据库。相反 - 使用内存队列,所有生产者都会将数据和消费者推送到这个队列中。您仍然可以将数据插入到sqlite表中以处理进程崩溃并且某些项目未处理的情况。以下是一些代码(出于说明目的 - 在您的实际应用程序中,您将不会有Thread.Sleep
当然这样):
class Program {
static readonly BlockingCollection<ItemToProcess> _queue = new BlockingCollection<ItemToProcess>(new ConcurrentQueue<ItemToProcess>());
static readonly CancellationTokenSource _cts = new CancellationTokenSource();
static void Main(string[] args) {
// get all unprocessed items from database here and insert into queue
var producerThread = StartProducer(_cts.Token);
var consumerThread = StartConsumer();
Console.ReadKey();
// cancel
_cts.Cancel();
// wait for producer thread to finish
producerThread.Join();
// notify there will be no more items
_queue.CompleteAdding();
// wait for consumer to finish
consumerThread.Join();
}
static Thread StartProducer(CancellationToken ct) {
var thread = new Thread(() => {
while (!ct.IsCancellationRequested) {
// also insert into database here
_queue.Add(new ItemToProcess() {
Value = "value"
});
// imitate delay
Thread.Sleep(5000);
}
}) {
IsBackground = true
};
thread.Start();
return thread;
}
static Thread StartConsumer() {
var thread = new Thread(() => {
foreach (var item in _queue.GetConsumingEnumerable()) {
try {
// process
Console.WriteLine(item.Value);
// delete from database here
}
catch (Exception ex) {
// handle
}
}
}) {
IsBackground = true
};
thread.Start();
return thread;
}
}
class ItemToProcess
{
public string Value { get; set; }
}
答案 2 :(得分:0)
你的任务超出了五秒循环,所以它当然只会触发一次。