Swift: как прервать процедуру сортировки

Я хочу дать пользователям возможность остановить процедуру сортировки, если она занимает слишком много времени.

Я пробовал использовать DispatchWorkItem.cancel. Однако на самом деле это не останавливает уже запущенные процессы.

let myArray = [String]() // potentially 230M elements!
...
workItem = DispatchWorkItem {
    let result = myArray.sorted()
    DispatchQueue.main.async {
    print ("done")
    }
}

// если процесс слишком длинный, пользователь нажимает "Отмена" => workItem.cancel() // не останавливает сортировку

Как я могу убить ветку workItem?

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

1 ответ

Как вы уже поняли, невозможно убить рабочий элемент без периодической проверки. isCancelled и вручную выполнить ранний выход, если он установлен.

Есть два варианта:

  1. Вы можете использовать sorted(by:), тест на isCancelledтам, выкидывая ошибку, если он отменен. Таким образом достигается желаемый ранний выход.

    Это может выглядеть так:

    func cancellableSort() -> DispatchWorkItem {
        var item: DispatchWorkItem!
        item = DispatchWorkItem() {
            let unsortedArray = (0..<10_000_000).shuffled()
            let sortedArray = try? unsortedArray.sorted { (obj1, obj2) -> Bool in
                if item.isCancelled {
                    throw SortError.cancelled
                }
                return obj1 < obj2
            }
            // do something with your sorted array
            item = nil
        }
        DispatchQueue.global().async(execute: item)
        return item
    }
    

    где

    enum SortError: Error {
        case cancelled
    }
    

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

  2. Вы можете просто написать свою собственную процедуру сортировки, вставив свой собственный тест isCancelledвнутри алгоритма. Это дает вам больше контроля над тем, где именно вы проводите тест (т. Е. Вы можете делать это не для каждого сравнения, а на каком-то более высоком уровне цикла в алгоритме, тем самым минимизируя влияние на производительность). А учитывая количество записей, это дает вам возможность выбрать алгоритм, наиболее подходящий для вашего набора данных.

Очевидно, что при тестировании этих альтернатив убедитесь, что вы тестируете оптимизированные / выпускаемые сборки, чтобы ваши результаты не были искажены настройками сборки.

Кроме того, вы можете подумать об использовании OperationТоже, поскольку его обработка отмены более элегантна, ИМХО. Кроме того, у вас может быть специальный объект для операции сортировки, что будет чище.

Другие вопросы по тегам