Если система имеет узел , возможно использовать -p
print и -e
флаги сценария evaulate с JSON.parse
, чтобы вытащить любое требуемое значение.
Простой пример с использованием строки JSON { "foo": "bar" }
и вытаскивание значения «foo»:
$ node -pe 'JSON.parse(process.argv[1]).foo' '{ "foo": "bar" }'
bar
] Поскольку у нас есть доступ к cat
и другим утилитам, мы можем использовать это для файлов:
$ node -pe 'JSON.parse(process.argv[1]).foo' "$(cat foobar.json)"
bar
Или любой другой формат, такой как URL-адрес, содержащий JSON:
$ node -pe 'JSON.parse(process.argv[1]).name' "$(curl -s https://api.github.com/users/trevorsenior)"
Trevor Senior
Использовать группы отправки: см. здесь для примера «Ожидание групп заданий в очереди» в главе «Очереди отправки» в Руководстве по программированию параллельной работы библиотеки разработчиков iOS для разработчиков iOS
Ваш пример может выглядеть примерно так:
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
// block1
NSLog(@"Block1");
[NSThread sleepForTimeInterval:5.0];
NSLog(@"Block1 End");
});
dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
// block2
NSLog(@"Block2");
[NSThread sleepForTimeInterval:8.0];
NSLog(@"Block2 End");
});
dispatch_group_notify(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
// block3
NSLog(@"Block3");
});
// only for non-ARC projects, handled automatically in ARC-enabled projects.
dispatch_release(group);
и может выдавать такой вывод:
2012-08-11 16:10:18.049 Dispatch[11858:1e03] Block1
2012-08-11 16:10:18.052 Dispatch[11858:1d03] Block2
2012-08-11 16:10:23.051 Dispatch[11858:1e03] Block1 End
2012-08-11 16:10:26.053 Dispatch[11858:1d03] Block2 End
2012-08-11 16:10:26.054 Dispatch[11858:1d03] Block3
Ответы выше, все круто, но все они пропустили одно. group выполняет задачи (блоки) в потоке, в который он был введен, когда вы используете dispatch_group_enter
/ dispatch_group_leave
.
- (IBAction)buttonAction:(id)sender {
dispatch_queue_t demoQueue = dispatch_queue_create("com.demo.group", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(demoQueue, ^{
dispatch_group_t demoGroup = dispatch_group_create();
for(int i = 0; i < 10; i++) {
dispatch_group_enter(demoGroup);
[self testMethod:i
block:^{
dispatch_group_leave(demoGroup);
}];
}
dispatch_group_notify(demoGroup, dispatch_get_main_queue(), ^{
NSLog(@"All group tasks are done!");
});
});
}
- (void)testMethod:(NSInteger)index block:(void(^)(void))completeBlock {
NSLog(@"Group task started...%ld", index);
NSLog(@"Current thread is %@ thread", [NSThread isMainThread] ? @"main" : @"not main");
[NSThread sleepForTimeInterval:1.f];
if(completeBlock) {
completeBlock();
}
}
выполняется в созданной параллельной очереди demoQueue
. Если я не создаю какую-либо очередь, она запускается в основном потоке.
- (IBAction)buttonAction:(id)sender {
dispatch_group_t demoGroup = dispatch_group_create();
for(int i = 0; i < 10; i++) {
dispatch_group_enter(demoGroup);
[self testMethod:i
block:^{
dispatch_group_leave(demoGroup);
}];
}
dispatch_group_notify(demoGroup, dispatch_get_main_queue(), ^{
NSLog(@"All group tasks are done!");
});
}
- (void)testMethod:(NSInteger)index block:(void(^)(void))completeBlock {
NSLog(@"Group task started...%ld", index);
NSLog(@"Current thread is %@ thread", [NSThread isMainThread] ? @"main" : @"not main");
[NSThread sleepForTimeInterval:1.f];
if(completeBlock) {
completeBlock();
}
}
, и есть третий способ сделать задачи исполняемыми в другом потоке:
- (IBAction)buttonAction:(id)sender {
dispatch_queue_t demoQueue = dispatch_queue_create("com.demo.group", DISPATCH_QUEUE_CONCURRENT);
// dispatch_async(demoQueue, ^{
__weak ViewController* weakSelf = self;
dispatch_group_t demoGroup = dispatch_group_create();
for(int i = 0; i < 10; i++) {
dispatch_group_enter(demoGroup);
dispatch_async(demoQueue, ^{
[weakSelf testMethod:i
block:^{
dispatch_group_leave(demoGroup);
}];
});
}
dispatch_group_notify(demoGroup, dispatch_get_main_queue(), ^{
NSLog(@"All group tasks are done!");
});
// });
}
Конечно, поскольку Вы можете использовать dispatch_group_async
, чтобы получить то, что хотите.
Не сказать, что другие ответы не подходят для определенных обстоятельств, но это один фрагмент, который я всегда пользовался Google:
- (void)runSigninThenInvokeSelector:(SEL)signInDoneSel {
if (signInDoneSel) {
[self performSelector:signInDoneSel];
}
}
Расширение на Jörn Eyrich отвечает (повышайте его ответ, если вы продвигаете этот вариант), если у вас нет контроля над вызовами dispatch_async
для ваших блоков, как это может быть в случае блоков завершения асинхронизации, вы можете использовать GCD группы, использующие dispatch_group_enter
и dispatch_group_leave
.
В этом примере мы притворяемся, что computeInBackground
- это то, что мы не можем изменить (представьте, что это обратный вызов делегата, NSURLConnection completeHandler или что-то еще) и таким образом, у нас нет доступа к вызовам отправки.
// create a group
dispatch_group_t group = dispatch_group_create();
// pair a dispatch_group_enter for each dispatch_group_leave
dispatch_group_enter(group); // pair 1 enter
[self computeInBackground:1 completion:^{
NSLog(@"1 done");
dispatch_group_leave(group); // pair 1 leave
}];
// again... (and again...)
dispatch_group_enter(group); // pair 2 enter
[self computeInBackground:2 completion:^{
NSLog(@"2 done");
dispatch_group_leave(group); // pair 2 leave
}];
// Next, setup the code to execute after all the paired enter/leave calls.
//
// Option 1: Get a notification on a block that will be scheduled on the specified queue:
dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSLog(@"finally!");
});
// Option 2: Block an wait for the calls to complete in code already running
// (as cbartel points out, be careful with running this on the main/UI queue!):
//
// dispatch_group_wait(group, DISPATCH_TIME_FOREVER); // blocks current thread
// NSLog(@"finally!");
В этом примере computeInBackground: завершение: реализовано как:
- (void)computeInBackground:(int)no completion:(void (^)(void))block {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSLog(@"%d starting", no);
sleep(no*2);
block();
});
}
Выход (с отметками времени от run):
12:57:02.574 2 starting
12:57:02.574 1 starting
12:57:04.590 1 done
12:57:06.590 2 done
12:57:06.591 finally!
dispatch_queue_notify
, вероятно, лучше (если время блокировки не будет коротким).
– ɲeuroburɳ
20 October 2014 в 21:34
С 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 */
Первый ответ по существу правильный, но если вам нужен самый простой способ добиться желаемого результата, вот пример отдельного кода, демонстрирующий, как это сделать с помощью семафора (так же, как группы отправки работают за кулисами , JFYI):
#include <dispatch/dispatch.h>
#include <stdio.h>
main()
{
dispatch_queue_t myQ = dispatch_queue_create("my.conQ", DISPATCH_QUEUE_CONCURRENT);
dispatch_semaphore_t mySem = dispatch_semaphore_create(0);
dispatch_async(myQ, ^{ printf("Hi I'm block one!\n"); sleep(2); dispatch_semaphore_signal(mySem);});
dispatch_async(myQ, ^{ printf("Hi I'm block two!\n"); sleep(4); dispatch_semaphore_signal(mySem);});
dispatch_async(myQ, ^{ dispatch_semaphore_wait(mySem, DISPATCH_TIME_FOREVER); printf("Hi, I'm the final block!\n"); });
dispatch_main();
}
dispatch_semaphore_wait
. У вас есть два сигнала, поэтому вам нужно два ожидания. Как и ваше «завершение» блок запускается, как только первый блок сигнализирует семафор, но до того, как закончится другой блок; 2. Учитывая, что это вопрос iOS, я бы отговорил использовать dispatch_main
.
– Rob
25 October 2013 в 04:40
dispatch_semaphore_wait
будет разблокирован, как только будет вызван любой из методов dispatch_semaphore_signal
. Причина, по которой это может работать, заключается в том, что printf
для блоков «один» и «два» происходит немедленно, а printf
для «finally» происходит после ожидания - таким образом, после того, как блок спал за 2 секунд. Если вы поместите printf после вызовов sleep
, вы получите результат для «один», а затем через 2 секунды для «finally», а затем через 2 секунды для «two».
– ɲeuroburɳ
3 January 2014 в 19:48
Я знаю, что вы спросили о GCD, но если вы хотите, NSOperationQueue
также обрабатывает этот материал действительно изящно, например :
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"Starting 3");
}];
NSOperation *operation;
operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"Starting 1");
sleep(7);
NSLog(@"Finishing 1");
}];
[completionOperation addDependency:operation];
[queue addOperation:operation];
operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"Starting 2");
sleep(5);
NSLog(@"Finishing 2");
}];
[completionOperation addDependency:operation];
[queue addOperation:operation];
[queue addOperation:completionOperation];
NSOperation
, который является параллельным и устанавливает isFinished
, когда асинхронный процесс завершается. Тогда зависимости работают нормально.
– Rob
23 October 2013 в 19:23
dispatch_semaphore_wait
не будет выполняться в основной очереди и пока ваши сигналы и ожидания будут сбалансированы). Пока вы не блокируете основную очередь, семафорный подход прекрасен, если вам не нужна гибкость операций (например, возможность отменить их, способность контролировать степень параллелизма и т. Д.).
– Rob
25 October 2013 в 04:47
sleep()
! Я только добавил те sleep()
призывы к педагогическим причинам, чтобы блоки работали достаточно долго, чтобы вы могли видеть, что они работают одновременно. В этом тривиальном примере, в отсутствие sleep()
, эти два блока могут выполняться так быстро, что отправленный блок может начинаться и заканчиваться, прежде чем у вас будет возможность эмпирически наблюдать параллельное выполнение. Но не делайте sleep()
в своем коде.
– Rob
8 June 2017 в 14:06
maxConcurrentOperationCount
на 1
. Вы также можете установить приоритет операций как qualityOfService
, так и queuePriority
, но они имеют гораздо более тонкое влияние на приоритет задачи, чем зависимости и / или степень параллелизма в очереди.
– Rob
17 February 2018 в 19:02
dispatch_group_async
аналогиченdispatch_async
с добавленным параметром группы. Поэтому, если вы используете разные очереди для block1 и block2 или планируете их в одной и той же параллельной очереди, они могут запускаться одновременно; если вы планируете их в одной и той же последовательной очереди, они будут запускаться серийно. Это ничем не отличается от планирования блоков без групп. – Jörn Eyrich 11 August 2012 в 15:12