C# 我需要在递归算法期间停止执行
我在选择正确的方法来实现我的目标方面遇到了问题。 我在做算法教学系统,我在用C。我需要将我的算法分成几个步骤,每个步骤都包含一个递归。 我必须在每个步骤后停止执行,然后用户可以使用GUI中的按钮移动到下一个步骤(下一个递归) 搜索后,线程是正确的选择,但我发现了几种方法:C# 我需要在递归算法期间停止执行,c#,multithreading,recursion,C#,Multithreading,Recursion,我在选择正确的方法来实现我的目标方面遇到了问题。 我在做算法教学系统,我在用C。我需要将我的算法分成几个步骤,每个步骤都包含一个递归。 我必须在每个步骤后停止执行,然后用户可以使用GUI中的按钮移动到下一个步骤(下一个递归) 搜索后,线程是正确的选择,但我发现了几种方法: (线程。睡眠/中断):没有工作,我的GUI冻结了 (暂停/恢复):我读到使用它是个坏主意 (Waithandles):还在读关于他们的书 (监视等待/恢复) 我没有太多的时间来尝试和阅读所有以前的方法,请帮助我选择最适合我
- (线程。睡眠/中断):没有工作,我的GUI冻结了
- (暂停/恢复):我读到使用它是个坏主意
- (Waithandles):还在读关于他们的书
- (监视等待/恢复)
我没有太多的时间来尝试和阅读所有以前的方法,请帮助我选择最适合我的系统的方法。任何建议都非常欢迎 如果您想在用户界面继续交互的情况下“在后台”工作,或者如果您想将一个缓慢的任务拆分为多个处理器核,则只需要使用线程 您所描述的内容听起来好像只需要编写一个线程:
- 记住用户在序列中的位置李>
- 每次他们点击你的按钮,执行下一步
如果您希望使用线程,那么您可以使用AutoResetEvent来允许线程循环执行这些步骤,并在每次迭代中等待一个。然后,每当用户单击按钮开始下一步时,您的用户界面就会发出该事件的信号。(您还需要在步骤完成时通知UI,以便用户只能按顺序运行这些步骤,因为您可以在开始步骤时设置button.Enabled=false,而线程可以在完成步骤时使用button.Invoke来设置Enabled=true)。但是,对于您所描述的内容,线程听起来过于复杂。您列出的所有内容都将阻止执行,如果在主线程中执行代码,则会冻结UI 如果您只需要挂起操作,然后恢复操作或取消操作,那么您必须将计算移动到单独的线程中,以便冻结它不会影响UI
你也可以从不同的角度来处理你的问题。您可以重新设计算法,以便可以从任意点重新启动它们-将递归堆栈设置为外部并将其作为参数传递只要您使用正确的方法,线程都是好的。我想说,从以下步骤开始:
可能会有帮助。您正使用waithandles朝着正确的方向前进
尝试使用。我认为这是一种实现目标的方法。从根本上说,这个问题并不是关于递归或多线程的,它只是这样: 如何在GUI应用程序的后台执行长时间运行的操作,使应用程序保持响应 实现您自己的线程模型是而不是,特别是当您刚刚开始学习多线程/异步操作时。NET Framework已经有了一个组件来完成您想要做的事情:,它可以在Winforms和WPF(以及几乎任何其他体系结构)中工作 使用
BackgroundWorker
可以非常非常轻松地完成您想要的任务。在这个例子中,我将假设Winforms,但这是一个简单的例子
显然,您还必须连接dowwork
和RunWorkerCompleted
事件,并确保在BackgroundWorker
上将worker支持扫描单元设置为true
。之后,使用以下命令运行操作:
bwRecursive.RunWorkerAsync(someTreeNode);
并通过以下方式取消:
bwRecursive.CancelAsync();
这里唯一的问题是,您说您希望在每个“步骤”之后暂停(而不是停止)执行。我可能会使用一个自动resetEvent
,它是一种事件类型,每次等待成功时都会重置其信号(“就绪”)状态。同样,只需集成几行代码:
public class MyForm : Form
{
private AutoResetEvent continueEvent = new AutoResetEvent(false);
// Previous BackgroundWorker code would go here
private void ExecuteRecursiveOperation(MyTreeNode node)
{
if (bwRecursive.CancellationPending)
return;
foreach (MyTreeNode childNode in node.ChildNodes)
{
continueEvent.WaitOne(); // <--- This is the new code
if (bwRecursive.CancellationPending)
break;
ExecuteRecursiveOperation(childNode);
}
}
private void btnContinue_Click(object sender, EventArgs e)
{
continueEvent.Set();
}
private void btnCancel_Click(object sender, EventArgs e)
{
bwRecursive.CancelAsync();
continueEvent.Set();
}
private void btnStart_Click(object sender, EventArgs e)
{
continueEvent.Set();
bwRecursive.RunWorkerAsync(...);
}
}
公共类MyForm:Form
{
私有自动恢复事件continueEvent=新自动恢复事件(false);
//以前的BackgroundWorker代码将放在这里
私有void ExecuteCursiveOperation(MyTreeNode节点)
{
if(bwRecursive.CancellationPending)
返回;
foreach(node.ChildNodes中的MyTreeNode childNode)
{
continueEvent.WaitOne()如果您对递归教学感兴趣,同时允许算法在每次迭代中暂停,您可能需要考虑创建一个状态管理器类,它封装算法并公开一个显式堆栈。递归算法实际上是一种基于堆栈的算法,因此能够运行单个迭代并查看。堆栈的内容将有助于演示递归实际上是如何运行的。我可以想象如下:
public struct AlgorithmParameters
{
public readonly int Parameter1;
public readonly int Parameter2;
public AlgorithmParameters(int parameter1, int parameter2)
{
Parameter1 = parameter1;
Parameter2 = parameter2;
}
}
public class RecursiveAlgorithm
{
private Stack<AlgorithmParameters> _parameterStack = new Stack<AlgorithmParameters>();
public IEnumerable<AlgorithmParameters> ParameterStack
{
get { return _parameterStack; }
}
public IEnumerable<RecursiveAlgorithm> RunAlgorithm(int parameter1, int parameter2)
{
return RunAlgorithm(new AlgorithmParameters(parameter1, parameter2));
}
public IEnumerable<RecursiveAlgorithm> RunAlgorithm(AlgorithmParameters parameters)
{
//Push parameters onto the stack
_parameterStack.Push(parameters);
//Return the current state of the algorithm before we start running
yield return this;
//Now execute the algorithm and return subsequent states
foreach (var state in Execute())
yield return state;
}
private IEnumerable<RecursiveAlgorithm> Execute()
{
//Get the parameters for this recursive call
var parameters = _parameterStack.Pop();
//Some algorithm implementation here...
//If the algorithm calls itself, do this:
int newParameter1 = 2; //Parameters determined above...
int newParameter2 = 5;
foreach (var state in RunAlgorithm(newParameter1, newParameter2))
yield return state;
//More implementation here...
//We've finished one recursive call, so return the current state
yield return this;
}
}
公共结构算法参数
{
公共只读int参数1;
公共只读int参数2;
公共算法参数(int参数1、int参数2)
{
参数1=参数1;
参数2=参数2;
}
}
公共类递归算法
{
私有堆栈_参数堆栈=新堆栈();
公共IEnumerable参数堆栈
{
获取{return\u parameterStack;}
}
公共IEnumerable运行算法(int参数1、int参数2)
{
返回RunAlgorithm(新算法参数(参数1,参数2));
}
公共IEnumerable运行算法(AlgorithmParameters)
{
//将参数推送到堆栈上
_参数堆栈
public struct AlgorithmParameters
{
public readonly int Parameter1;
public readonly int Parameter2;
public AlgorithmParameters(int parameter1, int parameter2)
{
Parameter1 = parameter1;
Parameter2 = parameter2;
}
}
public class RecursiveAlgorithm
{
private Stack<AlgorithmParameters> _parameterStack = new Stack<AlgorithmParameters>();
public IEnumerable<AlgorithmParameters> ParameterStack
{
get { return _parameterStack; }
}
public IEnumerable<RecursiveAlgorithm> RunAlgorithm(int parameter1, int parameter2)
{
return RunAlgorithm(new AlgorithmParameters(parameter1, parameter2));
}
public IEnumerable<RecursiveAlgorithm> RunAlgorithm(AlgorithmParameters parameters)
{
//Push parameters onto the stack
_parameterStack.Push(parameters);
//Return the current state of the algorithm before we start running
yield return this;
//Now execute the algorithm and return subsequent states
foreach (var state in Execute())
yield return state;
}
private IEnumerable<RecursiveAlgorithm> Execute()
{
//Get the parameters for this recursive call
var parameters = _parameterStack.Pop();
//Some algorithm implementation here...
//If the algorithm calls itself, do this:
int newParameter1 = 2; //Parameters determined above...
int newParameter2 = 5;
foreach (var state in RunAlgorithm(newParameter1, newParameter2))
yield return state;
//More implementation here...
//We've finished one recursive call, so return the current state
yield return this;
}
}
class MainWnd : Form{
/*
* A typical recursive factorial function would be
* implemented something like this:
*/
double Factorial(int n){
return (double)n * Factorial(n - 1);
}
/*
* Alternatively, factorial can be implemented iteratively:
*/
double Factorial(int n){
double product = n;
while(--n > 1)
product *= n;
return product;
}
/*
* Let's break the logic up into steps, so that it
* saves its state between steps and resumes where
* it left off for the next step.
*/
int factorialN;
double factorialProduct;
void BeginSteppedFactorial(int n){
factorialProduct = n;
factorialN = n - 1;
}
bool StepFactorial(){
if(factorialN <= 1)
return true; // we're done, the result is ready
factorialProduct *= factorialN--;
return false; // we're not yet done, call the next step
}
double GetSteppedFactorialResult(){return factorialProduct;}
static void Main(){Application.Run(new MainWnd());}
MainWnd(){
BeginSteppedFactorial(32);
Label lbl = new Label(){
AutoSize = true,
Location = new Point(10, 10),
Text = GetSteppedFactorialResult().ToString(),
Parent = this
};
Button btn = new Button(){
Location = new Point(10, 30),
Text = "Next Step",
Parent = this
};
btn.Click += (s, e)=>{
if(StepFactorial()){
btn.Text = "Finished";
btn.Enabled = false;
}
lbl.Text = GetSteppedFactorialResult().ToString();
};
}
}