Ожидание DispatchSemaphore для определенных c объектов потока? - PullRequest
0 голосов
/ 19 апреля 2020

Сегодня я реализовал семафор, и он поднял несколько вопросов о семафорах, потоках и очередях. Являются ли мои следующие записи точными?

let semaphore = DispatchSemaphore(value: 1)
let serialQueue = DispatchQueue(label: "serial")

someAsyncMethod {

    serialQueue.async {

        // When someAsyncMethod returns, this queue, behind the scenes,
        // creates a Thread/NSThread object and approaches the
        // semaphore and it is this thread object that decrements
        // the semaphore counter.

        // The next time someAsyncMethod returns, a new thread object
        // is created behind the scenes (by the queue) and this thread
        // object is made to wait until something (anything) signals
        // it is done.

        semaphore.wait()

        // do work...
        someMethod()

    }

}

func someMethod() {

    // do work...

    // This task may ultimately be on a different thread than
    // where it started despite being in the same queue
    // (since not every task is guaranteed to run on the same thread)
    // but it doesn't matter, any object can signal the semaphore.

    semaphore.signal()

}
  1. Отвечают ли семафоры на указанные c объекты / экземпляры потоков?
  2. Создается ли новый объект / экземпляр потоков каждый раз someAsyncMethod возвращается и входит в очередь?

Ответы [ 3 ]

0 голосов
/ 20 апреля 2020

Основы таковы:

A queue - инструмент для управления коллекцией задач.

Каждая задача выполняется в потоке .

A семафор - это способ координации задач, который может выполняться в разных потоках.

Независимо от того, создает ли каждая задача новый поток, или только некоторые задачи, или, может быть, все задачи, выполняемые в одном потоке полностью до Grand Central Dispatch . GCD освобождает вас от бремени беспокойства о потоках. Потоки будут создаваться, уничтожаться или повторно использоваться, если GCD сочтет нужным, в соответствии с возможностями, ресурсами и нагрузкой вашей системы.

Это просто вежливый способ сказать «перестаньте думать о потоках». Предположим, что каждая задача будет выполняться в своем собственном потоке в свое время (за исключением очень специальных очередей, таких как Main). Является ли поток, в котором фактически выполняется задача, новым потоком или повторно используемым потоком, и будет ли этот поток уничтожен после выполнения задачи или будет повторно использован для другой задачи - это область человека, находящегося за занавесом.

Если вам нужно согласовать пул ресурсов или дождаться завершения набора задач, тогда вы используете семафоры и / или любые инструменты на основе очередей, такие как последовательные очереди, группы диспетчеризации, барьеры и т. Д.

Надеюсь, это поможет.

0 голосов
/ 22 апреля 2020

Давайте разберемся с ними по одному:

someAsyncMethod {

    serialQueue.async {

        // When someAsyncMethod returns, this queue, behind the scenes,
        // creates a Thread/NSThread object and approaches the
        // semaphore and it is this thread object that decrements
        // the semaphore counter.

        // The next time someAsyncMethod returns, a new thread object
        // is created behind the scenes (by the queue) and this thread
        // object is made to wait until something (anything) signals
        // it is done.

        semaphore.wait()

        // do work...
        someMethod()
    }
}

Сначала небольшая деталь, но async не «создает» темы. GCD имеет пул рабочих потоков, и async просто захватывает один из этих свободных рабочих потоков. (Вот почему GCD является производительным, поскольку он избегает создания / уничтожения потоков все время, что является дорогостоящим упражнением. Он использует aws в своем пуле рабочих потоков.)

Во второй раз, когда вы вызываете async в той же последовательной очереди, вы можете получить тот же поток в следующий раз. Или вы можете получить другой рабочий поток из пула. У вас нет никаких гарантий в любом случае. Ваша единственная уверенность в том, что очередь является последовательной (потому что вы определили ее таковой).

Но, да, если семафор начинался со счетчика 1, то в первый раз он просто уменьшит счетчик и продолжит работу. , И, да, если этот семафор еще не был сигнализирован к тому моменту, когда вы добрались до этой секунды wait, да, он будет ждать signal.

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

У вас тогда было:

func someMethod() {

    // do work...

    // This task may ultimately be on a different thread than
    // where it started despite being in the same queue
    // (since not every task is guaranteed to run on the same thread)
    // but it doesn't matter, any object can signal the semaphore.

    semaphore.signal()

}

Этот код, поскольку он был вызван изнутри serialQueue.async предыдущего блока кода, он все равно будет работать в том же потоке, из которого вы вызывали someMethod.

Так что, следовательно, этот код не совсем имеет смысла. Вы никогда не будете signal из того же потока, который вызовет wait в том же потоке. Весь смысл семафоров в том, что один поток может wait для сигнала из другого потока.

Например, это может иметь смысл, если, например, someMethod делает что-то эквивалентное to:

func someMethod() {
    someOtherQueue.async {
        // do work...

        // Because this is dispatched to a different queue and we know is
        // now running on a different thread, now the semaphore has some 
        // utility, because it only works if it’s a different thread than
        // where we’ll later call `wait`...

        semaphore.signal()
    }
}

Теперь все это поднимает вопрос о назначении последовательной очереди вместе с этим семафором. Боюсь, что, пытаясь абстрагироваться от несвязанных деталей вашей кодовой базы, вы сделали это слишком абстрактным. Поэтому сложно посоветовать вам лучший шаблон без понимания более широкой проблемы, которую пытался решить этот код.

Но, без обид, почти наверняка будут намного лучшие подходы. Мы не можем просто не консультировать на основании предоставленной информации.


В заключение вы задали два вопроса:

  1. Отвечают ли семафоры на Speci c объектов / экземпляров потока?

Нет. Это для одного потока, чтобы сигнализировать другому, другому потоку. Но нет никаких других ограничений, кроме этого.

Создается ли новый объект / экземпляр потока каждый раз, когда someAsyncMethod возвращается и входит в очередь?

Как я уже говорил выше, замыкание отправляется в последовательную очередь с async может оказаться в том же рабочем потоке или в другом рабочем потоке.

Но это не настоящая проблема здесь. Реальная проблема заключается в том, что вызовы wait и signal выполняются из отдельных потоков, а не в том, являются ли последующие вызовы wait.

0 голосов
/ 20 апреля 2020

Семафоры не указываются для потоков c. Весь смысл в том, чтобы координировать действия между потоками, поэтому они должны использоваться несколькими потоками.

В этом конкретном случае c нет необходимости в семафоре (если это единственное использование), потому что вы ' использую последовательную очередь. По определению, последовательная очередь позволяет только одной из задач, поставленных в нее в очередь, запускаться одновременно, в порядке «первым пришел - первым вышел». То есть второй задаче не нужно ждать на семафоре, чтобы избежать одновременного выполнения с первой задачей, потому что даже запускать ее нельзя, пока первая задача не будет завершена.

Когда вы ставите задачу в очереди асинхронно вызывающий код может продолжаться немедленно. Задача больше похожа на объект данных, помещаемый в структуру данных (очередь). Grand Central Dispatch использует пул потоков, чтобы вытолкнуть задачу из очереди и выполнить ее. Должен ли он создавать новый поток или нет, зависит от того, достаточно ли уже свободных потоков в пуле.

...