简体   繁体   English

C++过滤管线

[英]C++ Filter Pipeline

I want to develop a Filter Pipeline for my Application.我想为我的应用程序开发一个过滤器管道。 The Pipeline should consist of any number of filters.管道应该由任意数量的过滤器组成。

For the Filters i declare an abstract base class like this:对于过滤器,我声明了一个抽象基 class,如下所示:

struct AbstractFilter {
    virtual void execute(const std::string& message) = 0;
    virtual ~AbstractFilter() = default;
}

Each Filter should inherit from this base class and implement the execute Method.每个过滤器都应该从这个基础 class 继承并实现execute方法。 Like so:像这样:

struct PrintMessage : public AbstractFilter {
    void execute(const std::string& message) override {
        std::cout << "Filter A " << message << '\n';
        //hand over message to next Filter

    }
}

struct Upper : public AbstractFilter {
    void execute(const std::string& message) override {
        std::string new_line;
        for (char c : line)
           new_line.push_back(std::toupper(c));
        //hand over message to next Filter
    }
}

struct WriteToFile : public AbstractFilter {
    void execute(const std::string& message) override {
        std::ofstream of{"test.txt"};
        of << message;
        of.close();
    }
}

EDIT 1:编辑1:

The Message should be send from one filter to the next in the Pipeline.消息应该从管道中的一个过滤器发送到下一个过滤器。 If the pipeline for example is like this:例如,如果管道是这样的:

Upper -- PrintMessage -- WriteToFile上 -- PrintMessage -- WriteToFile

The Message should pass all the 3 Filters.消息应通过所有 3 个过滤器。 (For example if Upper finished his work the message should be send to PrintMessage and so on) (例如,如果Upper完成了他的工作,则应该将消息发送到PrintMessage等等)

In the example above if the Message Hello World is send to the Pipeline the output should be:在上面的示例中,如果消息Hello World被发送到管道,则 output 应该是:

Console:
HELLO WORLD
test.txt:
HELLO WORLD

EDIT 2:编辑2:

The Filter only changes the content of the given Message.过滤器仅更改给定消息的内容。 The Type is not changed.类型没有改变。 Every Filter should work with for example strings or a given class.每个过滤器都应该使用例如字符串或给定的 class。 The Message is only forwarded to one recipient.消息仅转发给一位收件人。

My Question is now how to connect these Filters?我现在的问题是如何连接这些过滤器?

My First guess was to use Queues .我的第一个猜测是使用Queues So every Filter gets an Input and Output Queue.所以每个过滤器都有一个InputOutput队列。 For this i think every filter should run inside it's own Thread and be notified if data is added to his Input Queue.为此,我认为每个过滤器都应该在它自己的Thread内运行,并在数据添加到他的Input队列时得到通知。 (The Output Queue of for example FilterA is also the Input Queue of FilterB) (例如FilterA的Output队列也是FilterB的Input队列)

My Second Guess was to use the Chain Of Responsibility Pattern and boost::signals2 So FilterB for example connects to the Signal of FilterA.我的第二个猜测是使用责任链模式和boost::signals2所以 FilterB 例如连接到 FilterA 的信号。 FilterA calls these Filter when it finished it's work. FilterA 在完成工作后调用这些过滤器。

Which of the two solutions is the more flexible?两种解决方案哪个更灵活? Or is there even a better way to connect the Filters?或者有没有更好的方法来连接过滤器?

An additional Question is it also possible to run the whole Pipeline inside a Thread so that i can start multiple Pipelines?另一个问题是否也可以在一个线程内运行整个管道,以便我可以启动多个管道? (In the Example have 3 of the FilterA-FilterB-FilterD Pipeline up and running?) (在示例中,有 3 个 FilterA-FilterB-FilterD 管道启动并运行?)

I think AbstractFilter is not necessary and I'd suggest to use std::tuple to define a pipeline:我认为 AbstractFilter 不是必需的,我建议使用 std::tuple 来定义管道:

std::tuple<FilterA, FilterB> pipeline1;
std::tuple<FilterA, FilterB, FilterC ... > pipeline2;

To run a message through a pipeline do (using c++17):要通过管道运行消息(使用 c++17):

template<typename Pipeline>
void run_in_pipeline(const std::string& message, Pipeline& pipeline){
  std::apply([&message](auto&& ... filter) {
    (filter.execute(message), ...);
  }, pipeline);
}

If you care about performance and filters must be executed sequentially, I wouldn't suggest using multithreading or signal-slot patterns on a single pipeline.如果您关心性能并且过滤器必须按顺序执行,我不建议在单个管道上使用多线程或信号槽模式。 Consider instead run different pipelines on different threads if you are dealing with multithreading applications如果您正在处理多线程应用程序,请考虑在不同的线程上运行不同的管道

I would procede in this way: create a List with all the implemented versions of the Abstract Filter.我会以这种方式进行:创建一个包含所有已实现版本的抽象过滤器的列表。 So, following your exmample, after reading the input file I will get a list with:因此,按照您的示例,在阅读输入文件后,我将获得一个列表:

[0]:Upper 
[1]:PrintMessage
[2]:WriteToFile

Then a single thread (or a thread poll if you need to process many string at time) waiting a string in an input queue.然后一个线程(如果您需要一次处理许多字符串,则为线程轮询)在输入队列中等待一个字符串。 When a new string appears in the pool, the thread loops on the filter list and at the end posts the result in an output queue.当池中出现新字符串时,线程在过滤器列表上循环,最后将结果发布到 output 队列中。

If you want to run it in parallel, you need to find a way to keep the order of the input strings anche nelle stringhe di output.如果你想并行运行它,你需要找到一种方法来保持输入字符串 anche nelle stringhe di output 的顺序。

I believe the Chain of Responsibility pattern is simpler, allows for cleaner code and greater flexibility.我相信责任链模式更简单,允许更简洁的代码和更大的灵活性。

You do not need third-party libraries to implement it.您不需要第三方库来实现它。
What you call filters are actually handlers .您所说的过滤器实际上是处理程序 All handlers implement a common interface, defining a single method that could be named handle() and could even take an object as parameter to share state.所有处理程序都实现一个通用接口,定义一个可以命名为handle()的方法,甚至可以将 object 作为参数来共享 state。 Each handler stores a pointer to the next handler.每个处理程序都存储一个指向下一个处理程序的指针。 It may or may not call that method on it;它可能会或可能不会在其上调用该方法; in the latter case processing is halted, and it acts as a filter .在后一种情况下,处理停止,它充当过滤器

Running pipeline stages in parallel is more involved if some of them require the output of others as input.如果其中一些需要其他的 output 作为输入,则并行运行流水线阶段会更复杂。 For different pipelines to run in parallel, each one would run on its own thread, and you could use a queue to pass inputs to it.对于并行运行的不同管道,每个管道都将在自己的线程上运行,您可以使用队列将输入传递给它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM