C# 我应该使用反向工作线程还是编写自己的线程

C# 我应该使用反向工作线程还是编写自己的线程,c#,.net,winforms,C#,.net,Winforms,我们有一个程序,在主界面上有一个暂停按钮。当按下暂停按钮时,将保存一个时间戳,再次按下时,将创建另一个时间戳,计算两者之间的时间差,然后使用WebClient将所有3个值以及用户名发送到数据库。问题是,如果快速多次按下该按钮,则会出现获取所有发送数据的问题 我的想法是创建一个队列,而不是暂停按钮发送数据,它将把数据写入一个队列,然后让一个单独的线程检查队列并处理发送 使用计时器每x秒触发一个后台工作人员,以完成读取队列并发送数据的简单任务(如果队列在那里感觉像是过度杀戮/滥用)。我说的对吗?这更

我们有一个程序,在主界面上有一个暂停按钮。当按下暂停按钮时,将保存一个时间戳,再次按下时,将创建另一个时间戳,计算两者之间的时间差,然后使用
WebClient
将所有3个值以及用户名发送到数据库。问题是,如果快速多次按下该按钮,则会出现获取所有发送数据的问题

我的想法是创建一个队列,而不是暂停按钮发送数据,它将把数据写入一个队列,然后让一个单独的线程检查队列并处理发送


使用计时器每x秒触发一个后台工作人员,以完成读取队列并发送数据的简单任务(如果队列在那里感觉像是过度杀戮/滥用)。我说的对吗?这更像是一种常规的线程工作,还是后台工作人员的工作方式?

我个人使用线程。后台工作人员占用了我太多的代码。如果将线程作为全局变量,则可以随意终止或启动线程

请看这里:


对于线程和backgroundworker,您可以看到它们是否正在运行。如果它们正在运行,那么您可以禁用正在运行的按钮,或者使按钮不起任何作用。对于你正在做的事情,我推荐后台工作者。

我个人使用线程。后台工作人员占用了我太多的代码。如果将线程作为全局变量,则可以随意终止或启动线程

protected void btnPause_Click(object sender, EventArgs e)
    {
        System.ComponentModel.BackgroundWorker disableWorker = new System.ComponentModel.BackgroundWorker();
        disableWorker.DoWork += new System.ComponentModel.DoWorkEventHandler(disableWorker_DoWork);
        disableWorker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(disableWorker_RunWorkerCompleted);
        disableWorker.RunWorkerAsync();
    }

    void disableWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
    {
        btnPause.Enabled = true;
    }

    void disableWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
    {
        btnPause.Enabled = false;
        System.Threading.Thread.Sleep(10000);            
    }
请看这里:


对于线程和backgroundworker,您可以看到它们是否正在运行。如果它们正在运行,那么您可以禁用正在运行的按钮,或者使按钮不起任何作用。对于您正在做的事情,我建议您使用后台工作者。

我将使用包装在BlockingCollection类中的ConcurrentQueue,并使用任务来查看收集

protected void btnPause_Click(object sender, EventArgs e)
    {
        System.ComponentModel.BackgroundWorker disableWorker = new System.ComponentModel.BackgroundWorker();
        disableWorker.DoWork += new System.ComponentModel.DoWorkEventHandler(disableWorker_DoWork);
        disableWorker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(disableWorker_RunWorkerCompleted);
        disableWorker.RunWorkerAsync();
    }

    void disableWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
    {
        btnPause.Enabled = true;
    }

    void disableWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
    {
        btnPause.Enabled = false;
        System.Threading.Thread.Sleep(10000);            
    }
var pendingEntries = new BlockingCollection<List<Entry>>(new ConcurrentQueue<List<Entry>>());
var loggingTask = System.Threading.Tasks.Task.Factory.StartNew(ConsumerTask, pendingEntries);
添加完条目后,请调用以下命令:

pendingEntries.CompleteAdding();
一旦完成对队列中当前条目的处理,任务将退出foreach循环

然后,您可以等待任务完成,包括:

loggingTask.Wait();
pendingEntries.Dispose();

我将使用包装在BlockingCollection类中的ConcurrentQueue,并使用任务来监视集合

var pendingEntries = new BlockingCollection<List<Entry>>(new ConcurrentQueue<List<Entry>>());
var loggingTask = System.Threading.Tasks.Task.Factory.StartNew(ConsumerTask, pendingEntries);
添加完条目后,请调用以下命令:

pendingEntries.CompleteAdding();
一旦完成对队列中当前条目的处理,任务将退出foreach循环

然后,您可以等待任务完成,包括:

loggingTask.Wait();
pendingEntries.Dispose();

与其说我对风格感兴趣,不如说我对确保我没有虐待背景工作者感兴趣。虽然只是不使用背景工作者解决了虐待问题,如果它是一个。我不相信你滥用它。Backgroundworker应该能够处理所有事情。事实上,Backgroundworker也只是线程,所以你不能“滥用”它。但它比普通线程要重一些,因为它有一些现成的附加功能(报告进度事件、完成事件等等)。如果需要这些功能,请使用BgWorker。如果你不需要它们,就使用普通的线程。我对风格不感兴趣,而是想确保我没有滥用后台工作人员。虽然只是不使用背景工作者解决了虐待问题,如果它是一个。我不相信你滥用它。Backgroundworker应该能够处理所有事情。事实上,Backgroundworker也只是线程,所以你不能“滥用”它。但它比普通线程要重一些,因为它有一些现成的附加功能(报告进度事件、完成事件等等)。如果需要这些功能,请使用BgWorker。如果你不需要它们,就用一个普通的线程。“使用计时器……感觉像是过度杀戮/滥用”。“写我自己的帖子”可以说是矫枉过正。对于WinForms,
BackgroundWorker
是您的最佳选择,因为它在.NET 2+上可用。否则,请使用
任务
“使用计时器……感觉像是过度杀戮/滥用”。“写我自己的帖子”可以说是矫枉过正。对于WinForms,
BackgroundWorker
是您的最佳选择,因为它在.NET 2+上可用。否则,请使用
任务
考虑改进您的答案。考虑改进你的答案。我将暂停事件的数据存储在一个名为PauseEvent的类中,条目应该是我的PauseEvent类,还是有一个必须使用的预制条目类?我想在第二次单击暂停按钮时将事件添加到队列中。我只在每秒单击按钮时添加一个事件,所以我只需在PauseButton\u click()方法中调用
pendingtries.Add()
pendingtries.CompleteAdding()
?consumer方法只是进入MainForm类,对吗?PendingEntries和loggingtask定义会去哪里?在我的示例代码中,条目可以是您选择的任何内容。听起来你的PauseeEvent类可以去那里。你只需要调用pendingEntries.Add()。CompeteAdding仅在您完成任务后要关闭任务时使用。将pendingEntries和loggingTask放在您选择的任何位置。主窗体可能很好。您可能可以使用internet搜索找到更完整的示例。我将暂停事件的数据存储在一个名为PauseEvent的类中,条目应该是我的PauseEvent类,还是有一个必须使用的预制条目类?我想在第二次单击暂停按钮时将事件添加到队列中。我只在每秒单击按钮时添加一个事件,所以我只需在PauseButton\u click()方法中调用
pendingtries.Add()
pendingtries.CompleteAdding()
?consumer方法只是进入MainForm类,对吗?PendingEntries和loggingtask定义会去哪里?在我的示例代码中,条目可以是您选择的任何内容。听起来你的PauseeEvent类可以去那里。你只需要调用pendingEntries.Add()。CompeteAdding仅在您完成任务后要关闭任务时使用。将pendingEntries和loggingTask放在您选择的任何位置。市场关注度指数