程序设计:来电/被呼叫者困境,同步/手动切换上下文

时间:2015-04-05 20:18:08

标签: design-patterns asynchronous coroutine paradigms

我的问题涉及程序的一般设计。 当对象a想要向对象b发送信息时,有三种可能性:

  1. 控制在对象a和b之外,并且调用a和b的公共方法:

    b.TakeInformation(a.getInformation());
    
  2. 控制在b:
  3. 在这种情况下,b会按照自己的意愿行事,有时会要求a提供信息:

    class A {
      public Information getInformatino() {
        // code omitted
      }
      // code omitted
    }
    class B {
      // code omitted
      void foo() {
        while (bar()) {
          information = a.getInformation();
          DoSomeWork(information);
        }
      }
    }
    
    1. 控件位于a
    2. 在这种情况下,a会按照自己的意愿行事,有时它会产生信息:

      class A {
        // code omitted
        void foo() {
          while (bar()) {
            information = produceInformation()
            b.TakeInformation(information)
          }
        }
      }
      class B {
        // code omitted
        public void TakeInformation(information) {
          // code omitted
        }
      }
      

      我最感兴趣的是第四种可能性,ab都是来电者,而且没有一个是被调用者。

      在这种情况下,最简单的答案是:重写其中一个类,使其成为被调用者。

      这不能让我满意。例如,让我们假设一种奇怪的流,它不允许我通过调用方法ReadChar()aka getInformation()来读取字符,而是它是一个调用者,每次从它调用的输入读取一个字符b.giveInformation(character)

      假设我无法重写A类。然后想象我编写了一个B语言,它是某种语言的解析器。解析器B包含许多函数和帮助类,并在代码中的许多地方使用ReadChar。

      问题的解决方案需要重写B类,以便giveInformation(character)调用它而不是调用ReadChar()。这将是非常痛苦和不直观的。

      这个合成示例最优雅的解决方案是创建适配器,它启动A并存储所有字符,然后启动B并为其提供读取字符的nececarry接口。

      不幸的是,当AB类在两个方向上进行通信时,这不适用于其他情况。

      一般人如何解决这些问题?

      是否有一些编程语言具有非标准范例,此任务不会出现问题?

      我想到了几种可能的解决方案或方法。它们包括线程,管道,汇编语言或滥用惰性评估,但它们似乎都不够好或者我不知道如何使用它们。我将在答案中总结我的想法。

      感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

我需要的东西可以使用线程在伪代码中重写,如下所示:

class A {
  // code omitted
  void foo() {
    while (bar()) {
      information = produceInformation()
      wake thread b, send it information
      suspend this thread until result is received
      result = received result
      DoSomeWorkWithResult(result);
    }
  }
}

class B {
  // code omitted
  void foo() {
    while (bar()) {
      suspend this thread until information is received
      information = received information
      result = DoSomeWork(information);
      wake thread a, send it the result
    }
  }
}

然而,我所解决的任务的性质并不平行。实际上,不能同时执行任何代码行。只有被切换的上下文不是并行运行的。所以我怀疑是否有必要使用线程。 (而且我也不确定线程​​的开销是多少。)

即使没有并行性,我也可能会用线程编写代码。但是,我通常对如何解决这些类型的通信的可能方式感兴趣。我确信它是可以解决的 - 至少在一些编程语言中。

在c ++和汇编语言中,一切皆有可能。如何在那里使用两个堆栈并在上下文之间手动切换?

在任何编程语言中都可以将A,B编译为两个可执行文件。 A的标准输出可以是B的B输入。并且通过使用命名管道,B的输出可以再次输入A.(但是它需要对象的序列化和反序列化。我认为这是不明智的。我还希望有一个可执行文件。)

在具有惰性评估的编程语言中,可能会以某种方式滥用此范例来解决此类任务。

E.g。在c#中,可以在课程B中实施IEnumerator()。当A产生新信息时,将调用MoveNext()。控件在B内并暂停此“线程”的错觉。可以通过致电yield return;

来确保

这种方法的缺点是'线程'只能在其主要方法中暂停。或者,必须将相同的技巧重新应用于所有其他应该挂起该线程的方法。

也许c#中的异步方法可以某种方式用于解决此类任务。但是如何?

答案 1 :(得分:0)

你的设计答案很糟糕,比原始问题的设计更糟糕。您在B类和A类之间添加了不必要的耦合。

你看起来可能是observer pattern。在观察者模式中,类只需要通知订阅者已经执行了一个操作,而不知道订阅了哪个类以及在通知时将执行什么。