Образ докера и хост несовместимы

Я был вдохновлен ответом Святослава Павленко: использование блокирующих MPI-коммуникаций для обеспечения последовательного вывода. В то время как Уэсли Блэнд указывает, что MPI не будет построен для последовательного выхода. Поэтому, если мы хотим выводить данные, имеет смысл либо иметь каждый выходной процессор (не сталкивающийся). В качестве альтернативы, если порядок данных важен (и он не слишком большой), рекомендуемый подход заключается в том, чтобы отправить все это на процессор (скажем, ранг 0), который затем правильно форматирует данные.

Мне , это, кажется, немного перебор, особенно когда данные могут быть строками переменной длины, что слишком часто является тем, что std::cout << "a=" << some_varible << " b=" << some_other_variable часто. Поэтому, если мы хотим получить скорую и грязную печать в порядке, мы можем использовать ответ Святослав Павленко для создания потока последовательного вывода. Это решение работает отлично, но его производительность сильно ухудшается со многими процессорами, поэтому не используйте его для вывода данных!

#include <iostream>
#include <sstream>
#include <mpi.h>

MPI Удержание:

int mpi_size;
int mpi_rank;

void init_mpi(int argc, char * argv[]) {
    MPI_Init(& argc, & argv);
    MPI_Comm_size(MPI_COMM_WORLD, & mpi_size);
    MPI_Comm_rank(MPI_COMM_WORLD, & mpi_rank);
}

void finalize_mpi() {
    MPI_Finalize();
}

Общее класс -purpose, который позволяет цепочку сообщений MPI

template<class T, MPI_Datatype MPI_T> class MPIChain{
    // Uses a chained MPI message (T) to coordinate serial execution of code (the content of the message is irrelevant).
    private:
        T message_out; // The messages aren't really used here
        T message_in;
        int size;
        int rank;

    public:
        void next(){
            // Send message to next core (if there is one)
            if(rank + 1 < size) {
            // MPI_Send - Performs a standard-mode blocking send.
            MPI_Send(& message_out, 1, MPI_T, rank + 1, 0, MPI_COMM_WORLD);
            }
        }

        void wait(int & msg_count) {
            // Waits for message to arrive. Message is well-formed if msg_count = 1
            MPI_Status status;

            // MPI_Probe - Blocking test for a message.
            MPI_Probe(MPI_ANY_SOURCE, 0, MPI_COMM_WORLD, & status);
            // MPI_Get_count - Gets the number of top level elements.
            MPI_Get_count(& status, MPI_T, & msg_count);

            if(msg_count == 1) {
                // MPI_Recv - Performs a standard-mode blocking receive.
                MPI_Recv(& message_in, msg_count, MPI_T, MPI_ANY_SOURCE, 0, MPI_COMM_WORLD, & status);
            }
        }

        MPIChain(T message_init, int c_rank, int c_size): message_out(message_init), size(c_size), rank(c_rank) {}

        int get_rank() const { return rank;}
        int get_size() const { return size;}
};

Теперь мы можем использовать наш класс MPIChain для создания нашего класса, который управляет потоком вывода:

class ChainStream : public MPIChain<int, MPI_INT> {
    // Uses the MPIChain class to implement a ostream with a serial operator<< implementation.
    private:
        std::ostream & s_out;

    public:
        ChainStream(std::ostream & os, int c_rank, int c_size)
            : MPIChain<int, MPI_INT>(0, c_rank, c_size), s_out(os) {};

        ChainStream & operator<<(const std::string & os){
            if(this->get_rank() == 0) {
                this->s_out << os;
                // Initiate chain of MPI messages
                this->next();
            } else {
                int msg_count;
                // Wait untill a message arrives (MPIChain::wait uses a blocking test)
                this->wait(msg_count);
                if(msg_count == 1) {
                    // If the message is well-formed (i.e. only one message is recieved): output string
                    this->s_out << os;
                    // Pass onto the next member of the chain (if there is one)
                    this->next();
                }
            }

            // Ensure that the chain is resolved before returning the stream
            MPI_Barrier(MPI_COMM_WORLD);

            // Don't output the ostream! That would break the serial-in-time exuction.
            return *this;
       };
};

Обратите внимание на MPI_Barrier в конце operator<<. Это делается для того, чтобы код не начинал вторую цепочку вывода. Несмотря на то, что это можно было бы перемещать за пределы operator<<, я решил, что я бы поставил его здесь, так как это все равно предполагается серийным выходом ....

Объединяя все это:

int main(int argc, char * argv[]) {
    init_mpi(argc, argv);

    ChainStream cs(std::cout, mpi_rank, mpi_size);

    std::stringstream str_1, str_2, str_3;
    str_1 << "FIRST:  " << "MPI_SIZE = " << mpi_size << " RANK = " << mpi_rank << std::endl;
    str_2 << "SECOND: " << "MPI_SIZE = " << mpi_size << " RANK = " << mpi_rank << std::endl;
    str_3 << "THIRD:  " << "MPI_SIZE = " << mpi_size << " RANK = " << mpi_rank << std::endl;

    cs << str_1.str() << str_2.str() << str_3.str();
    // Equivalent to:
    //cs << str_1.str();
    //cs << str_2.str();
    //cs << str_3.str();

    finalize_mpi();
}

Обратите внимание, что мы конкатенируем строки str_1, str_2, str_3 перед , мы отправляем им экземпляр ChainStream. Обычно можно было бы сделать что-то вроде:

std::cout << "a" << "b" << "c"" << std::endl

, но это применимо operator<< слева направо, и мы хотим, чтобы строки были готовы к выходу перед последовательным запуском через каждый процесс.

g++-7 -O3 -lmpi serial_io_obj.cpp -o serial_io_obj
mpirun -n 10 ./serial_io_obj

Выходы:

FIRST:  MPI_SIZE = 10 RANK = 0
FIRST:  MPI_SIZE = 10 RANK = 1
FIRST:  MPI_SIZE = 10 RANK = 2
FIRST:  MPI_SIZE = 10 RANK = 3
FIRST:  MPI_SIZE = 10 RANK = 4
FIRST:  MPI_SIZE = 10 RANK = 5
FIRST:  MPI_SIZE = 10 RANK = 6
FIRST:  MPI_SIZE = 10 RANK = 7
FIRST:  MPI_SIZE = 10 RANK = 8
FIRST:  MPI_SIZE = 10 RANK = 9
SECOND: MPI_SIZE = 10 RANK = 0
SECOND: MPI_SIZE = 10 RANK = 1
SECOND: MPI_SIZE = 10 RANK = 2
SECOND: MPI_SIZE = 10 RANK = 3
SECOND: MPI_SIZE = 10 RANK = 4
SECOND: MPI_SIZE = 10 RANK = 5
SECOND: MPI_SIZE = 10 RANK = 6
SECOND: MPI_SIZE = 10 RANK = 7
SECOND: MPI_SIZE = 10 RANK = 8
SECOND: MPI_SIZE = 10 RANK = 9
THIRD:  MPI_SIZE = 10 RANK = 0
THIRD:  MPI_SIZE = 10 RANK = 1
THIRD:  MPI_SIZE = 10 RANK = 2
THIRD:  MPI_SIZE = 10 RANK = 3
THIRD:  MPI_SIZE = 10 RANK = 4
THIRD:  MPI_SIZE = 10 RANK = 5
THIRD:  MPI_SIZE = 10 RANK = 6
THIRD:  MPI_SIZE = 10 RANK = 7
THIRD:  MPI_SIZE = 10 RANK = 8
THIRD:  MPI_SIZE = 10 RANK = 9
2
задан Aref 17 January 2019 в 05:08
поделиться

3 ответа

"Хост" является компьютером, что Вы работаете на контейнере - так, чтобы действительно относился к Вашему ноутбуку Win 10, если это - машина, которая выполняет Докера и является машиной, на которой Вы создали контейнер.

, вероятно, просто необходимо обновить к 1809 сборки Windows 10 (выпуск октября 2018). Я столкнулся с той же проблемой, и я заметил, что моя машина все еще выполняла 1803 - даже при том, что я беру автоматические обновления. Я просто перешел к обновлению окон и вручную проверил на обновления.

0
ответ дан JMarsch 17 January 2019 в 05:08
поделиться

Я получил похожую ошибку, когда попытался вытащить последнюю версию nanoserver для Windows:

PS C:\WINDOWS\system32> docker pull mcr.microsoft.com/windows/nanoserver:1809_amd64 
1809_amd64: Pulling from windows/nanoserver
a Windows version 10.0.17763-based image is incompatible with a 10.0.17134 host

Если я посмотрю на dxdiag (run -> dxdiag), то у меня появится:

[ 111]

Так что, я думаю, вот откуда приходит номер с хоста. Это означает, что я пытаюсь получить контейнерную версию, которая является слишком новой для моего компьютера. Я нашел эту веб-страницу:

https://docs.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/version-compatibility

Там это четко говорится, что версия 2019 не поддерживается на моей ОС. Думаю, мне нужно подождать! Я думаю, что вы можете проверить версии вашего ноутбука и сервера и посмотреть, совместимы ли они с образом докера, который вы пытаетесь запустить.

0
ответ дан MrBerta 17 January 2019 в 05:08
поделиться

Одной из возможных причин может быть то, что докер, работающий на вашем хосте, настроен для работы с контейнерами Linux, что является поведением по умолчанию. Обратите внимание, что несмотря на тот факт, что хост является машиной Windows (Windows 10 и, вероятно, сервер Windows, на который вы ссылались) могут работать с образами на основе Linux в Docker.

Сетевое ядро ​​ASP звучит примерно как контейнер Windows, поэтому вам, вероятно, следует «переключить» режим: в интерфейсе Docker есть пункт меню «Переключиться на контейнер Windows». Вы пробовали это?

0
ответ дан Mark Bramnik 17 January 2019 в 05:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: