С Swift 3, Grand Central Dispatch предлагает множество способов решить вашу проблему. В соответствии с вашими потребностями вы можете выбрать один из шести шаблонов, показанных в следующих фрагментах игровой площадки.
DispatchGroup
, DispatchGroup
notify(qos:flags:queue:execute:)
и DispatchQueue
async(group:qos:flags:execute:)
Руководство по программированию параллельного программирования Apple Developer указывает на DispatchGroup
:
Группы отправки - это способ блокировать поток, пока не завершится выполнение одной или нескольких задач. Вы можете использовать это поведение в тех местах, где вы не можете добиться прогресса, пока все указанные задачи не будут завершены. Например, после отправки нескольких задач для вычисления некоторых данных вы можете использовать группу для ожидания этих задач, а затем обрабатывать результаты, когда они будут выполнены.
import Foundation import PlaygroundSupport PlaygroundPage.current.needsIndefiniteExecution = true let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent) let group = DispatchGroup() queue.async(group: group) { print("#1 started") Thread.sleep(forTimeInterval: 5) print("#1 finished") } queue.async(group: group) { print("#2 started") Thread.sleep(forTimeInterval: 2) print("#2 finished") } group.notify(queue: queue) { print("#3 finished") } /* prints: #1 started #2 started #2 finished #1 finished #3 finished */
# 2. Используя
DispatchGroup
,DispatchGroup
wait()
,DispatchGroup
enter()
иDispatchGroup
leave()
import Foundation import PlaygroundSupport PlaygroundPage.current.needsIndefiniteExecution = true let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent) let group = DispatchGroup() group.enter() queue.async { print("#1 started") Thread.sleep(forTimeInterval: 5) print("#1 finished") group.leave() } group.enter() queue.async { print("#2 started") Thread.sleep(forTimeInterval: 2) print("#2 finished") group.leave() } queue.async { group.wait() print("#3 finished") } /* prints: #1 started #2 started #2 finished #1 finished #3 finished */
Обратите внимание, что вы также можете смешать
DispatchGroup
wait()
сDispatchQueue
async(group:qos:flags:execute:)
или миксDispatchGroup
enter()
иDispatchGroup
leave()
сDispatchGroup
notify(qos:flags:queue:execute:)
.# 3. Использование свойства
DispatchWorkItemFlags
barrier
иDispatchQueue
DispatchQueue
async(group:qos:flags:execute:)
Учебное пособие по центральному диспетчерскому центру для Swift 3: Part 1/2 статья Raywenderlich.com дает определение барьеров :
Барьеры отправки - это группа функций, выполняющих узкие места в последовательном стиле при работе с параллельными очередями. [...] Когда вы отправляете
DispatchWorkItem
в очередь отправки, вы можете установить флаги, чтобы указать, что он должен быть единственным элементом, выполняемым в указанной очереди за это конкретное время. Это означает, что все элементы, отправленные в очередь до барьера отправки, должны завершиться до выполненияDispatchWorkItem
.Использование:
import Foundation import PlaygroundSupport PlaygroundPage.current.needsIndefiniteExecution = true let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent) queue.async { print("#1 started") Thread.sleep(forTimeInterval: 5) print("#1 finished") } queue.async { print("#2 started") Thread.sleep(forTimeInterval: 2) print("#2 finished") } queue.async(flags: .barrier) { print("#3 finished") } /* prints: #1 started #2 started #2 finished #1 finished #3 finished */
# 4. Используя
DispatchWorkItem
, свойствоDispatchWorkItemFlags
barrier
иDispatchQueue
async(execute:)
import Foundation import PlaygroundSupport PlaygroundPage.current.needsIndefiniteExecution = true let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent) queue.async { print("#1 started") Thread.sleep(forTimeInterval: 5) print("#1 finished") } queue.async { print("#2 started") Thread.sleep(forTimeInterval: 2) print("#2 finished") } let dispatchWorkItem = DispatchWorkItem(qos: .default, flags: .barrier) { print("#3 finished") } queue.async(execute: dispatchWorkItem) /* prints: #1 started #2 started #2 finished #1 finished #3 finished */
# 5. Используя
DispatchSemaphore
,DispatchSemaphore
wait()
иDispatchSemaphore
signal()
методыСоруш Ханлоу написал следующие строки в Сообщение в блоге GCD Handbook :
Используя семафор, мы можем заблокировать поток в течение произвольного промежутка времени, пока сигнал из другого потока не будет послал. Семафоры, как и остальные GCD, являются потокобезопасными, и их можно запускать из любого места. Семафоры могут использоваться, когда есть асинхронный API, который вам нужно сделать синхронным, но вы не можете его изменить.
Справочник API разработчика Apple также дает следующее обсуждение для
DispatchSemaphore
init(value:)
initializer:Передача нуля для значения полезна, когда двум потокам необходимо согласовать завершение определенного события. Передача значения больше нуля полезно для управления конечным пулом ресурсов, где размер пула равен значению.
Использование:
import Foundation import PlaygroundSupport PlaygroundPage.current.needsIndefiniteExecution = true let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent) let semaphore = DispatchSemaphore(value: 0) queue.async { print("#1 started") Thread.sleep(forTimeInterval: 5) print("#1 finished") semaphore.signal() } queue.async { print("#2 started") Thread.sleep(forTimeInterval: 2) print("#2 finished") semaphore.signal() } queue.async { semaphore.wait() semaphore.wait() print("#3 finished") } /* prints: #1 started #2 started #2 finished #1 finished #3 finished */
# 6. Используя
OperationQueue
иBlockOperation
Справочник API разработчика Apple содержит информацию о
OperationQueue
:Операционные очереди используют библиотеку
libdispatch
(также известную как Grand Central Dispatch), чтобы инициировать выполнение своих операций.Использование:
import Foundation import PlaygroundSupport PlaygroundPage.current.needsIndefiniteExecution = true let operationQueue = OperationQueue() let blockOne = BlockOperation { print("#1 started") Thread.sleep(forTimeInterval: 5) print("#1 finished") } let blockTwo = BlockOperation { print("#2 started") Thread.sleep(forTimeInterval: 2) print("#2 finished") } let blockThree = BlockOperation { print("#3 finished") } blockThree.addDependency(blockOne) blockThree.addDependency(blockTwo) operationQueue.addOperations([blockThree, blockTwo, blockOne], waitUntilFinished: false) /* prints: #1 started #2 started #2 finished #1 finished #3 finished or #2 started #1 started #2 finished #1 finished #3 finished */
Короче говоря, вы не можете использовать лямбда-клиент boto3 в вашем примере. Однако вы можете отслеживать ваши журналы CloudWatch.
1) Разместите частичные результаты, которые вы хотели бы видеть, в регистраторе внутри вашей лямбда-функции.
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def my_logging_handler(event, context):
results = "something half done"
logger.info('MY PARTIAL RESULTS'.format(results))
logger.error('something went wrong')
return 'Hello from Lambda!'
2) Запустите вашу лямбду асинхронно
response = client.invoke(
FunctionName='string',
InvocationType='Event' # To invoke asynchronously InvocationType must be Event,
LogType='None'|'Tail',
ClientContext='string',
Payload=b'bytes'|file,
Qualifier='string'
)
3) Создайте цикл, который вызывает GetLogEvents в течение определенного промежутка времени для потока журнала, связанного с вашей лямбдой. [ 118]
Request Syntax:
{
"endTime": number,
"limit": number,
"logGroupName": "string",
"logStreamName": "string",
"nextToken": "string",
"startFromHead": boolean,
"startTime": number
}
4) Извлечь частичные результаты из ответа потока журнала
Response Syntax:
{
"events": [
{
"ingestionTime": number,
"message": "string", # The partial response you posted will be seen here
"timestamp": number
}
],
"nextBackwardToken": "string",
"nextForwardToken": "string"
}