摘要:今天给大家安利一个 C++ 界的 "瑞士军刀"——Folly!这个由 Facebook 开发的开源库,可是大厂工程师们处理高并发、大数据的秘密武器。就像一个装满黑科技的百宝箱,里面藏着高性能容器、异步编程框架、内存管理黑魔法等实用工具,让你的代码性能直接起飞!
今天给大家安利一个 C++ 界的 "瑞士军刀"——Folly!这个由 Facebook 开发的开源库,可是大厂工程师们处理高并发、大数据的秘密武器。就像一个装满黑科技的百宝箱,里面藏着高性能容器、异步编程框架、内存管理黑魔法等实用工具,让你的代码性能直接起飞!
高性能:专为大规模分布式系统设计,比 STL 快 3-10 倍。在 Facebook 内部,每天要处理海量的用户请求和数据传输,如果使用普通的 C++ 库,系统很容易就会因为性能瓶颈而崩溃。而 Folly 库经过了 Facebook 内部大规模系统的验证和优化,在处理高并发、大数据时,能够以极高的效率运行,大大提升了系统的吞吐量和响应速度。例如在处理用户动态的展示时,Folly 库可以快速地从海量的数据库中检索并处理数据,让用户能够在极短的时间内看到自己关注的内容。轻量化:按需引入,无冗余依赖。在一些资源有限的场景中,比如移动设备端的应用开发,或者对资源消耗要求严格的嵌入式系统开发中,Folly 库的轻量化特性就显得尤为重要。它不会像一些其他库一样,引入大量不必要的依赖,增加系统的负担。开发者可以根据自己的实际需求,选择性地引入 Folly 库中的组件,这不仅减少了编译时间,还降低了程序的内存占用。现代化:完美兼容 C++11/14/17,支持协程等新特性。随着 C++ 语言的不断发展,新的特性不断涌现,Folly 库也紧跟时代的步伐,积极支持这些新特性。例如在 C++17 中引入的结构化绑定(structured bindings),可以方便地将一个对象的成员解包成独立的变量,Folly 库对这一特性的支持,使得开发者在使用 Folly 库进行开发时,能够充分利用 C++17 的新特性,编写出更加简洁、高效的代码。场景全覆盖:网络通信、内存管理、并发控制样样精通。以 Facebook 的社交网络服务为例,在网络通信方面,Folly 库中的 wangle 子模块提供了一套完整的服务器框架,用于构建高性能的 TCP/HTTP 服务,能够高效地处理大量用户的请求和响应。在内存管理方面,Folly 库提供了内存池和内存分配器等工具,能够有效地减少内存碎片,提高内存的使用效率,确保系统在长时间运行过程中不会因为内存问题而出现故障。在并发控制方面,Folly 库提供了锁、原子操作和并发容器等工具,使得多线程编程更加安全和高效,能够保证在高并发的情况下,用户数据的一致性和完整性。在 C++ 的世界里,容器就像是我们的 “数据收纳盒”,而 Folly 提供了一系列性能爆表的容器,让 STL 都黯然失色。就拿 FBvector 来说,它在动态数组的基础上进行了深度优化,在一些测试场景中,相比原生的 vector,FBVector 的性能提升了 20%。这意味着在处理大量数据时,FBVector 能以更快的速度完成插入、删除和查找操作。想象一下,在一个社交平台的用户动态加载功能中,需要频繁地向动态列表中插入新的动态数据,如果使用原生 vector,随着数据量的增加,插入操作的耗时会逐渐变长,导致用户等待时间增加。而 FBVector 凭借其高效的内存管理和算法优化,能够快速地完成插入操作,让用户能够即时看到最新的动态。
再看 F14HashMap,它是 Folly 库中专门为高并发场景设计的哈希表。与 STL 中的 unordered_map 相比,F14HashMap 支持原子操作,这意味着在多线程环境下,它能够保证数据的一致性和线程安全性,避免了数据竞争和并发访问时的错误。在分布式缓存系统中,多个线程可能同时对缓存进行读写操作,如果使用普通的哈希表,很容易出现数据不一致的情况。而 F14HashMap 的原子操作特性,使得它能够在高并发的读写场景下稳定运行,确保缓存数据的准确性和一致性。
在现代编程中,异步编程已经成为提高程序性能和响应速度的关键技术。Folly 库提供了一套强大的异步编程框架,基于 Future/Promise 模型和 EventBase 事件循环,让你轻松实现非阻塞 I/O 操作。
Future 和 Promise 就像是一对默契的搭档,Promise 负责异步操作的执行和结果的设置,而 Future 则用于获取异步操作的结果。通过它们,你可以将耗时的操作放在后台线程执行,主线程可以继续处理其他任务,大大提高了程序的并发性能。例如,在一个网络爬虫程序中,需要从多个网页中获取数据,如果使用同步操作,每获取一个网页的数据都需要等待网络请求完成,这会导致程序的执行效率非常低。而使用 Folly 的 Future/Promise 模型,你可以同时发起多个网络请求,主线程可以继续执行其他任务,当某个网络请求完成后,通过 Future 获取数据进行后续处理,大大提高了爬虫的效率。
EventBase 事件循环则是 Folly 异步编程的核心,它负责管理和调度异步事件,使得程序能够高效地处理大量的并发请求。在一个高性能的 Web 服务器中,EventBase 可以监听多个客户端的连接请求,当有新的连接到来时,它会将连接事件分发给相应的处理函数进行处理,同时不会阻塞其他事件的处理,确保服务器能够快速响应大量客户端的请求。
内存管理一直是 C++ 编程中的一个难点,而 Folly 库提供了一系列先进的内存管理技术,让你的程序在内存使用上更加高效和稳定。
FBString 采用了独特的三级存储策略,针对不同长度的字符串,分别使用栈上存储(SSO)、堆上直接拷贝(Eager Copy)和写时复制(COW)。对于短字符串,直接存储在栈上,避免了堆内存分配的开销;对于中等长度的字符串,采用堆上直接拷贝,保证了操作的高效性;对于长字符串,则使用写时复制技术,只有在真正需要修改字符串时才进行拷贝,大大减少了内存的占用和拷贝操作的开销。在一个日志记录系统中,经常会有大量的短字符串记录,如果使用普通的字符串存储方式,频繁的堆内存分配会导致性能下降。而 FBString 的 SSO 策略,使得短字符串能够直接存储在栈上,大大提高了日志记录的效率。
AtomicAllocator 是 Folly 库中的一个线程缓存内存分配器,它通过线程本地缓存来减少内存碎片的产生。在多线程环境下,每个线程都有自己的内存缓存,当线程需要分配内存时,首先从本地缓存中获取,如果缓存中没有足够的内存,则从全局内存池中获取。这样可以减少线程之间对内存分配的竞争,提高内存分配的效率,同时也减少了内存碎片的产生,使得内存的使用更加高效。在一个多线程的图像处理程序中,每个线程都需要频繁地分配和释放内存来存储图像数据,如果使用普通的内存分配器,很容易产生内存碎片,导致内存利用率下降。而 AtomicAllocator 的线程缓存机制,能够有效地减少内存碎片的产生,提高内存的使用效率,保证图像处理程序的高效运行。
Folly 库还对智能指针进行了扩展,引入了 DiscriminatedPtr。它支持多类型变体,可以存储不同类型的指针,并且在运行时能够自动识别指针的类型。这在一些需要处理多种数据类型的场景中非常有用,例如在一个通用的数据处理框架中,可能需要处理不同类型的数据,使用 DiscriminatedPtr 可以方便地存储和管理这些不同类型的数据指针,提高代码的灵活性和可维护性。
想要使用 Folly 库,首先得把它安装到你的开发环境中。以 Ubuntu 系统为例,你可以通过以下步骤完成安装。先确保你的系统已经安装了必要的依赖项,如 g++、cmake 等。然后从 Folly 的官方代码仓库(https://github.com/facebook/folly)克隆代码到本地。
进入克隆后的目录,创建一个 build 文件夹,在 build 文件夹中执行 cmake .. 命令进行项目配置,再执行 make 命令进行编译,最后使用 sudo make install 命令完成安装。安装完成后,在你的项目中引入 Folly 库的头文件时,就可以像引入其他普通头文件一样,例如 #include 。
FBVector:动态数组的进化版FBVector 是 Folly 库中对动态数组的一种优化实现。它在内存管理和性能方面都有出色的表现。比如,当你需要创建一个存储整数的动态数组时,使用 FBVector 可以这样写:
#include #include int main {folly::FBVector myVector;myVector.push_back(1);myVector.push_back(2);myVector.push_back(3);for (const auto& num : myVector) {std::cout在这个例子中,我们创建了一个 FBVector 对象 myVector,并向其中添加了三个整数。然后通过范围 for 循环遍历 myVector,输出其中的元素。FBVector 的优势在于,它在插入和删除元素时,性能比原生的 vector 更高效,特别是在处理大量数据时,这种优势更加明显。
F14HashMap:高并发下的哈希神器F14HashMap 是 Folly 库中专门为高并发场景设计的哈希表。它支持原子操作,能够在多线程环境下保证数据的一致性和线程安全性。下面是一个简单的使用示例:
#include #include int main {folly::F14HashMap myMap;myMap.insert({1, "apple"});myMap.insert({2, "banana"});myMap.insert({3, "cherry"});auto it = myMap.find(2);if (it != myMap.end) {std::cout second在这个例子中,我们创建了一个 F14HashMap 对象 myMap,它的键是整数类型,值是字符串类型。我们向 myMap 中插入了三组键值对,然后通过 find 方法查找键为 2 的元素,如果找到了就输出其对应的值。
在多线程环境下,多个线程可以用 ConcurrentHashMap 进行插入、查找和删除操作,而不用担心数据竞争和并发访问时的错误。
在网络编程中,Folly 库的 EventBase 和 Asyncsocket 为我们提供了高效处理网络事件和异步 I/O 的能力。接下来,我们通过一个简单的 TCP 服务器示例,来感受一下 Folly 在网络编程中的魅力。
#include #include #include #include #include class EchoSession : public folly::AsyncSocket::ReadCallback {public:EchoSession(folly::EventBase* evb, folly::AsyncSocket* sock): socket_(sock), evb_(evb) {}void readDataAvailable(size_t len) override {std::unique_ptr buffer(new char[len]);socket_->read(buffer.get, len);std::string data(buffer.get, len);std::cout write(data.c_str, data.size);}void readEOF override {std::cout close;}void readErr(const folly::AsyncSocketException& ex) override {std::cerr close;}private:folly::AsyncSocket* socket_;folly::EventBase* evb_;};class EchoServer : public folly::AsyncServerSocket::AcceptCallback {public:EchoServer(folly::EventBase* evb) : evb_(evb) {}void connectionAccepted(int fd) override {auto socket = folly::AsyncSocket::newSocket(evb_, fd);auto session = std::make_shared(evb_, socket.get);socket->setReadCallback(session.get);socket->resumeRead;}private:folly::EventBase* evb_;};int main {folly::EventBase evb;EchoServer server(&evb);folly::AsyncServerSocket serverSocket(&evb);serverSocket.bind(9090);serverSocket.listen(128);serverSocket.startAccepting(&server);std::cout在这个示例中,我们创建了一个简单的回显服务器。EchoSession 类负责处理每个客户端连接的读写操作,当有数据可读时,它会读取数据并回显给客户端;当连接关闭或出现错误时,它会进行相应的处理。EchoServer 类负责接受新的客户端连接,每当有新的连接到来时,它会创建一个新的 EchoSession 对象来处理该连接。在 main 函数中,我们初始化了一个 EventBase 对象,创建了 EchoServer 和 AsyncServerSocket 对象,并将服务器绑定到 9090 端口开始监听。最后,通过调用 evb.loopForever 启动事件循环,使服务器能够持续处理客户端的连接和请求。这个示例展示了 Folly 在网络编程中的基本用法,通过 EventBase 和 AsyncSocket 的配合,我们可以轻松地构建出高性能的网络服务器。
#### `Arena.h`, `ThreadCachedArena.h`Simple arena for memory allocation: multiple allocations get freed allat once. With threaded version.#### [`AtomicHashMap.h`](AtomicHashMap.md), `AtomicHashArray.h`, `AtomicLinkedList.h`, ...High-performance atomic data-structures. Many of these are built with very specifictradeoffs and constraints in mind that make them faster than their more generalcounterparts. Each header should contain information about what these tradeoffs are.#### `Baton.h`A Baton allows a thread to block once and be awoken: it captures a single handoff. It isessentially a (very small, very fast) semaphore that supports only a single call to `sem_call`and `sem_wait`.#### [`Benchmark.h`](Benchmark.md)A small framework for benchmarking code. Client code registersbenchmarks, optionally with an argument that dictates the scale of thebenchmark (iterations, working set size etc). The framework runsbenchmarks (subject to a command-line flag) and produces formattedoutput with timing information.#### `Bits.h`Various bit manipulation utilities optimized for speed; includes functionsthat wrap the[ffsl(l)](http://linux.die.net/man/3/ffsll) primitives in a uniforminterface.#### `ConcurrentSkipList.h`An implementation of the structure described in [A Provably CorrectScalable Concurrent SkipList](http://people.csail.mit.edu/shanir/publications/OPODIS2006-BA.pdf)by Herlihy et al.#### [`Conv.h`](Conv.md)A variety of data conversion routines (notably to and from string),optimized for speed and safety.#### `Demangle.h`Pretty-printing C++ types.#### `DiscriminatedPtr.h`Similar to `std::variant`, but restricted to pointers only. Uses thehighest-order unused 16 bits in a pointer as discriminator. So`sizeof(DiscriminatedPtr) == sizeof(void*)`.#### [`dynamic.h`](Dynamic.md)Dynamically-typed object, created with JSON objects in mind. `DynamicConverter.h` isa utility for efficiently converting from a `dynamic` to a more concrete structure whenthe scheme is known (e.g. json -> `map`).#### `EvictingCacheMap.h`A simple LRU hash map.#### [`FBString.h`](FBString.md)A drop-in implementation of `std::string` with a variety of optimizations.#### [`FBVector.h`](FBVector.md)A mostly drop-in implementation of `std::vector` with a variety ofoptimizations.#### `File.h`A C++ abstraction around files.#### `Fingerprint.h`Rabin fingerprinting.#### [`Function.h`](Function.md)A polymorphic wrapper for callables similar to `std::function` but not copyable and therefore able to wrap non-copyable callables, such as lambdas that capture move-only types like `std::unique_ptr` or `folly::Promise`.#### [`futures/`](Futures.md)Futures is a framework for expressing asynchronous code in C++ using the Promise/Future pattern.#### [`Format.h`](Format.md)Python-style formatting utilities.#### `gen/`This library makes it possible to write declarative comprehensions forprocessing sequences of values efficiently in C++ akin to C#'s LINQ.#### [`GroupVarint.h`](GroupVarint.md)[Group Varintencoding](http://www.ir.uwaterloo.ca/book/addenda-06-index-compression.html)for 32-bit values.#### `IPAddress.h`A collection of utilities to deal with IPAddresses, including ipv4 and ipv6.#### `io/`A collection of useful of abstractions for high-performance io. This is heavily relied uponin Facebook's internally networking code.#### `Hash.h`Various popular hash function implementations.#### [`Histogram.h`](Histogram.md)A simple class for collecting histogram data.#### `IntrusiveList.h`Convenience type definitions for using `boost::intrusive_list`.#### `json.h`JSON serializer and deserializer. Uses `dynamic.h`.#### `Likely.h`Wrappers around [`__builtin_expect`](http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html).#### `Malloc.h`, `Memory.h`Memory allocation helpers, particularly when using jemalloc.#### `MicroSpinLock.h`A really, *really* small spinlock for fine-grained locking of lots of teeny-tiny data.#### `MPMCQueue.h`MPMCQueue is a high-performance bounded concurrent queue thatsupports multiple producers, multiple consumers, and optional blocking.The queue has a fixed capacity, for which all memory will be allocatedup front.The additional utility `MPMCPipeline.h` is an extension that lets youchain several queues together with processing steps in between.#### [`PackedSyncPtr.h`]A highly specialized data structure consisting of a pointer, a 1-bitspin lock, and a 15-bit integer, all inside one 64-bit word.#### [`Poly.h`]A class template that makes it relatively easy to define a type-erasingpolymorphic object wrapper.#### `Preprocessor.h`Necessarily evil stuff.#### [`ProducerConsumerQueue.h`]Lock free single-reader, single-writer queue.#### `Random.h`Defines only one function---`randomNumberSeed`.#### `Range.h`Boost-style range facility and the `StringPiece` specialization.#### `RWSpinLock.h`Fast and compact reader-writer spin lock.#### `ScopeGuard.h`C++11 incarnation of the old [ScopeGuard](http://drdobbs.com/184403758) idiom.#### `Singleton.h`A singleton to rule the singletons. This is an attempt to insert a layer betweenC++ statics and the fiasco that ensues, so that things can be created, and destroyed,correctly upon program creation, program end and sometimes `dlopen` and `fork`.Singletons are bad for you, but this may help.#### [`SmallLocks.h`](SmallLocks.md)Very small spin locks (1 byte and 1 bit).#### `small_vector.h`Vector with the small buffer optimization and an optional embedded`PicoSpinLock`.#### `sorted_vector_types.h`Collections similar to `std::map` but implemented as sorted vectors.#### `stats/`A collection of efficient utilities for collecting statistics:* time series counters, gauges, histograms, and quantiles;* single-pass mean and variance.#### `StlAllocator.h`STL allocator wrapping a simple allocate/deallocate interface.#### `String.h`String utilities that connect `folly::fbstring` with `std::string`.#### `Subprocess.h`Subprocess library, modeled after Python's subprocess module.#### [`Synchronized.h`](Synchronized.md)High-level synchronization library.#### `System.h`Demangling and errno utilities.#### [`ThreadCachedInt.h`](ThreadCachedInt.md)High-performance atomic increment using thread caching.#### [`ThreadLocal.h`](ThreadLocal.md)Improved thread local storage for non-trivial types.#### `TimeoutQueue.h`Queue with per-item timeout.#### `Traits.h`Type traits that complement those defined in the standard C++11 header``.#### `Unicode.h`Defines the `codePointToUtf8` function.#### `Uri.h`A collection of utilities to deal with URIs.在互联网时代,每天都有海量的数据在网络中传输,高性能服务器就像是信息高速公路上的交通枢纽,承担着处理和转发大量请求的重任。Folly 库在这方面发挥着至关重要的作用,以 Facebook 为例,作为全球最大的社交网络平台之一,Facebook 每天要处理数亿甚至数十亿的用户请求,包括用户登录、动态加载、消息发送等各种操作。这些请求不仅数量巨大,而且对响应速度要求极高,用户希望在点击按钮的瞬间就能看到结果。
Folly 库中的高性能容器、异步编程框架和内存管理工具,为 Facebook 的服务器开发提供了强大的支持。在处理用户动态展示时,F14HashMap 可以快速地从海量的用户数据中检索出特定用户的动态信息,FBVector 则用于高效地存储和处理这些动态数据,确保用户能够在极短的时间内看到自己关注的内容。同时,基于 EventBase 的异步 I/O 操作,使得服务器能够同时处理大量的并发请求,而不会因为阻塞而导致响应延迟。在 Facebook 的搜索功能中,当用户输入关键词进行搜索时,服务器会同时处理多个相关的查询请求,Folly 库的异步编程框架能够将这些请求分配到不同的线程或进程中进行处理,大大提高了搜索的效率和响应速度。
在金融领域,时间就是金钱,每一秒的延迟都可能导致巨大的损失。高频交易系统需要在极短的时间内对市场数据进行分析和处理,做出交易决策。Folly 库的高性能和异步编程特性,使其成为实时数据处理的理想选择。在高频交易系统中,需要实时接收来自交易所的行情数据,这些数据包含了股票价格、成交量等重要信息,数据量非常大且更新频率极高。Folly 库的高性能容器可以高效地存储和处理这些数据,而异步编程框架则能够实现对数据的实时分析和处理,及时捕捉市场的变化并做出相应的交易决策。
假设一个高频交易系统需要实时监测某只股票的价格变化,当价格达到某个预设的阈值时,自动触发买入或卖出操作。使用 Folly 库,系统可以通过异步 I/O 操作实时接收股票行情数据,将数据存储在 FBVector 中进行管理。然后,利用 Folly 库的高性能计算工具对数据进行实时分析,一旦价格满足预设条件,立即触发交易操作。Folly 库的高效性能保证了整个过程的快速和准确,使得交易能够在毫秒级的时间内完成,为投资者赢得了宝贵的时间优势。
在游戏开发中,尤其是大型 3A 游戏,内存管理是一个关键问题。游戏需要加载大量的资源,如纹理、模型、音频等,这些资源占用的内存空间非常大。如果内存管理不善,很容易导致游戏卡顿、掉帧甚至崩溃,严重影响玩家的游戏体验。Folly 库的内存管理工具,如 FBString 的三级存储策略、AtomicAllocator 的线程缓存机制等,能够有效地减少内存碎片,提高内存的使用效率,为游戏引擎的资源管理提供了优化方案。
在当今的分布式系统中,微服务架构已经成为主流。微服务架构将一个大型的应用程序拆分成多个小型的服务,每个服务独立运行、独立部署,通过网络进行通信和协作。这种架构模式提高了系统的可扩展性、可维护性和灵活性,但也带来了一些挑战,如服务之间的通信、并发控制、数据一致性等。Folly 库提供了丰富的网络通信和并发编程工具,为微服务框架的构建提供了底层支持。
Folly 库的网络通信工具,如 AsyncSocket 和 EventBase,可以实现高效的网络通信,确保服务之间的数据传输快速、可靠。在并发控制方面,Folly 库的并发容器和同步原语,如 F14HashMap 和 Mutex,可以保证在高并发情况下,各个微服务对共享数据的访问安全,避免数据竞争和不一致的问题。Folly 库还提供了一些分布式系统常用的工具,如分布式锁、分布式缓存等,这些工具进一步增强了微服务框架的功能和性能,使得分布式系统能够更加稳定、高效地运行。
GitHub 仓库:Folly 的 GitHub 仓库(https://github.com/facebook/folly)是获取最新代码、提交问题和参与社区讨论的绝佳场所。在这里,你可以查看 Folly 的完整代码实现,学习其他开发者的优秀实践,还能及时了解 Folly 的更新动态,第一时间获取新功能和性能优化。学习社区:Stack Overflow 上的 #folly - library 话题汇聚了全球 Folly 开发者,在这里你可以提问、分享经验,解决开发中遇到的各种难题。当你在使用 Folly 进行开发时,如果遇到了编译错误、运行时异常或者对某个功能的实现有疑问,都可以在这个社区中寻求帮助,其他开发者可能会根据自己的经验给出解决方案和建议。通过本文的入门指南,你已经掌握了 Folly 的基本概念和实战技巧。这个 Facebook 工程师爱不释手的宝藏库,能帮你轻松应对高并发、低延迟的编程挑战。
Folly里面的宝藏很多,里面有很多其他的概念(看上面的图或者官网),等待大家去一一发掘!!!
来源:TigerOnHill一点号