Folly для C++: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Folly для C++: полное руководство с примерами

1. Что это и зачем нужна

Folly (Facebook Open-source LibrarY) — это библиотека компонентов C++, разработанная и используемая в Facebook (ныне Meta). Она представляет собой набор высокопроизводительных, хорошо протестированных и современных утилит, которые заполняют пробелы в стандартной библиотеке C++ (std) и Boost. Folly не является заменой STL, а скорее её расширением, предоставляющим решения для типичных задач, возникающих при разработке крупномасштабных распределённых систем и высоконагруженных серверов.

Зачем нужна Folly? В современной C++ разработке часто требуются инструменты, которых нет в стандартной библиотеке: эффективные контейнеры с определёнными свойствами (например, F14HashMap), инструменты для асинхронного программирования (Futures), атомарные операции с оптимизированными барьерами памяти (AtomicHashMap), работа с памятью без блокировок (ConcurrentSkipList) и множество других низкоуровневых оптимизаций. Folly предоставляет всё это в виде готовых, проверенных в бою компонентов. Она особенно полезна для разработчиков, пишущих производительный серверный код, работающих с сетевыми протоколами, большими объёмами данных или требующих детерминированного поведения в многопоточных сценариях.

Ключевое преимущество Folly — её ориентация на производительность и корректность. Многие алгоритмы в Folly реализованы с использованием новейших возможностей C++ (C++14/17/20) и учитывают особенности современных процессоров (кеши, предсказание ветвлений, SIMD-инструкции). Это не просто "ещё одна библиотека", а набор инструментов, который позволяет писать код, который работает быстрее и эффективнее, чем аналогичные решения на чистом STL или Boost, особенно в условиях высокой конкурентности.

2. Установка

Folly — это библиотека на C++, поэтому она не устанавливается через pip или npm. Для её использования необходимо собрать библиотеку из исходного кода и подключить её к вашему проекту. Рекомендуемый способ — использование системы сборки CMake.

Установка через vcpkg (рекомендуется для Windows и Linux)

# Установите vcpkg, если он ещё не установлен
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh  # или bootstrap-vcpkg.bat для Windows
./vcpkg integrate install

# Установите Folly
./vcpkg install folly:x64-windows  # для Windows
./vcpkg install folly:x64-linux    # для Linux

Установка через Conan

pip install conan
conan remote add bincrafters https://api.bintray.com/conan/bincrafters/public-conan
conan install folly/2023.01.30@ -r bincrafters

Сборка из исходного кода (Linux/macOS)

git clone https://github.com/facebook/folly
cd folly
mkdir build && cd build
cmake ..
make -j$(nproc)
sudo make install

Подключение к проекту (CMake)

find_package(folly REQUIRED)
target_link_libraries(my_project PRIVATE Folly::folly)

3. Быстрый старт — минимальный рабочий пример

Следующий пример демонстрирует использование folly::Future для асинхронного выполнения задачи и folly::format для форматирования строк.

#include <iostream>
#include <folly/futures/Future.h>
#include <folly/Format.h>

using namespace folly;

int main() {
    // Асинхронная задача: вернуть число 42
    auto future = makeFuture(42);

    // Цепочка обработки: умножить на 2 и преобразовать в строку
    auto result = future
        .thenValue([](int x) { return x * 2; })
        .thenValue([](int x) { return format("Результат: {}", x); })
        .get(); // Блокируем поток до получения результата

    std::cout << result << std::endl; // Выведет: Результат: 84

    return 0;
}

Для компиляции этого примера используйте:

g++ -std=c++17 example.cpp -lfolly -lglog -lgflags -lpthread -o example

4. Основные методы/функции/классы

4.1 folly::Future и folly::Promise

Сигнатура (упрощённо):

template <class T>
class Future {
    Future& thenValue(Func&& func);
    T get();
    bool isReady() const;
};

template <class T>
class Promise {
    void setValue(T&& value);
    void setException(folly::exception_wrapper ew);
    Future<T> getFuture();
};

Что делает: Реализует паттерн Promise/Future для асинхронного программирования. Promise — поставщик результата, Future — потребитель. Позволяет строить цепочки асинхронных операций без блокировок.

Пример:

#include <folly/futures/Future.h>
#include <iostream>
#include <thread>

using namespace folly;

int main() {
    Promise<int> promise;
    Future<int> future = promise.getFuture();

    std::thread producer([&promise]() {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        promise.setValue(100);
    });

    // Асинхронно обрабатываем результат
    future.thenValue([](int val) {
        std::cout << "Получено: " << val << std::endl;
    });

    producer.join();
    // Ждём завершения всех Future (в реальном коде используйте EventBase)
    std::this_thread::sleep_for(std::chrono::seconds(2));
    return 0;
}

4.2 folly::F14HashMap и folly::F14FastSet

Сигнатура:

template <class Key, class Value, class Hash = ...>
class F14HashMap {
    Value& operator[](const Key& key);
    std::pair<iterator, bool> insert(const value_type& value);
    iterator find(const Key& key);
    size_t erase(const Key& key);
};

template <class Key, class Hash = ...>
class F14FastSet {
    std::pair<iterator, bool> insert(const Key& key);
    bool contains(const Key& key) const;
};

Что делает: Высокопроизводительные хэш-таблицы, оптимизированные для современных процессоров. Используют технику "swiss table" (Google's SwissTable), что обеспечивает высокую скорость вставки, поиска и удаления, особенно при работе с большими объёмами данных.

Пример:

#include <folly/container/F14Map.h>
#include <folly/container/F14Set.h>
#include <string>
#include <iostream>

int main() {
    folly::F14FastMap<std::string, int> ages;
    ages["Alice"] = 30;
    ages["Bob"] = 25;

    auto it = ages.find("Alice");
    if (it != ages.end()) {
        std::cout << "Alice's age: " << it->second << std::endl;
    }

    folly::F14FastSet<int> unique_numbers;
    unique_numbers.insert(1);
    unique_numbers.insert(2);
    unique_numbers.insert(1); // Не добавится

    std::cout << "Set contains 2: " << unique_numbers.contains(2) << std::endl;
    return 0;
}

4.3 folly::fbstring

Сигнатура:

class fbstring {
    fbstring(const char* s);
    fbstring(const fbstring& other);
    const char* c_str() const;
    size_t size() const;
    fbstring& operator+=(const fbstring& other);
    int compare(const fbstring& other) const;
};

Что делает: Альтернатива std::string с улучшенной производительностью. Использует Small String Optimization (SSO) с большим буфером (до 23 символов на 64-битных системах) и оптимизированные алгоритмы для работы с памятью.

Пример:

#include <folly/FBString.h>
#include <iostream>

int main() {
    folly::fbstring hello = "Hello, ";
    folly::fbstring world = "World!";

    hello += world;
    std::cout << hello << std::endl; // Hello, World!

    folly::fbstring small = "Hi"; // Хранится в стеке (SSO)
    folly::fbstring large = "This is a very long string that exceeds the SSO buffer"; // Хранится в куче

    std::cout << "Small size: " << small.size() << std::endl;
    std::cout << "Large size: " << large.size() << std::endl;
    return 0;
}

4.4 folly::format

Сигнатура:

template <class... Args>
fbstring format(fbstring fmt, Args&&... args);

template <class... Args>
void formatTo(fbstring& output, fbstring fmt, Args&&... args);

Что делает: Безопасная и эффективная альтернатива sprintf и std::ostringstream. Поддерживает позиционные аргументы, спецификаторы формата (как в Python) и работает быстрее, чем std::format (C++20) в некоторых сценариях.

Пример:

#include <folly/Format.h>
#include <iostream>

int main() {
    std::string name = "Alice";
    int age = 30;
    double salary = 75000.50;

    // Простое форматирование
    auto result = folly::format("Name: {}, Age: {}, Salary: {:.2f}", name, age, salary);
    std::cout << result << std::endl;

    // Позиционные аргументы
    auto result2 = folly::format("{1} is {0} years old", age, name);
    std::cout << result2 << std::endl;

    // Форматирование в существующую строку
    folly::fbstring output;
    folly::formatTo(output, "Hello, {}!", "World");
    std::cout << output << std::endl;
    return 0;
}

4.5 folly::AtomicHashMap

Сигнатура (упрощённо):

template <class Key, class Value, class Hash = ...>
class AtomicHashMap {
    bool insert(const Key& key, const Value& value);
    bool find(const Key& key, Value& value_out) const;
    Value* get(const Key& key);
    size_t size() const;
};

Что делает: Потокобезопасная хэш-таблица без блокировок (lock-free). Оптимизирована для сценариев с интенсивной записью из нескольких потоков. Использует атомарные операции и механизм "compare-and-swap" (CAS).

Пример:

#include <folly/AtomicHashMap.h>
#include <iostream>
#include <thread>
#include <vector>

int main() {
    folly::AtomicHashMap<int, int> map(1024); // Начальный размер

    std::vector<std::thread> threads;
    for (int i = 0; i < 10; ++i) {
        threads.emplace_back([&map, i]() {
            for (int j = 0; j < 100; ++j) {
                map.insert(i * 100 + j, i * 100 + j);
            }
        });
    }

    for (auto& t : threads) {
        t.join();
    }

    int value;
    if (map.find(42, value)) {
        std::cout << "Found value: " << value << std::endl;
    }

    std::cout << "Map size: " << map.size() << std::endl;
    return 0;
}

4.6 folly::ConcurrentSkipList

Сигнатура (упрощённо):

template <class T, class Compare = std::less<T>>
class ConcurrentSkipList {
    bool insert(const T& value);
    bool contains(const T& value) const;
    size_t erase(const T& value);
    class Accessor; // Для итерации
};

Что делает: Потокобезопасная реализация skip-list (список с пропусками). Поддерживает вставку, удаление и поиск за O(log n) в среднем. Не использует блокировки для чтения и минимальные блокировки для записи.

Пример:

#include <folly/concurrency/ConcurrentSkipList.h>
#include <iostream>

int main() {
    folly::ConcurrentSkipList<int> skiplist;

    skiplist.insert(10);
    skiplist.insert(5);
    skiplist.insert(20);
    skiplist.insert(15);

    std::cout << "Contains 10: " << skiplist.contains(10) << std::endl;
    std::cout << "Contains 7: " << skiplist.contains(7) &                    

Рекомендаций