使用 Facebook Folly 与 Conan
这篇博文旨在介绍 Facebook Folly 项目及其复杂的依赖关系链以及其用法。它还将展示 Conan 作为其安装及其依赖项的解决方案。此示例的源代码可以在 Github 上找到。
什么是 Folly
Folly 是 Facebook 开源库 的“首字母缩写”,一个用社区协作开发的 C++ 项目,在 Github 上颇受欢迎,拥有超过 11,000 星和 2,000 次分支。该项目于 2012 年通过 Facebook 推出,目标是打造一个完整的库,专注于易用性、开发速度以及作为现实世界解决方案的补充,包括
- 异步计算
- 字符串格式化
- 基准测试
- 动态类型
Folly 也通过 CppCon 版本向世界推出,例如在 CppCon 2017 上的 “Facebook C++ 库的经验”,并在 Github 上有广泛的文档。
为什么我的项目应该使用 Folly?
我们已经有了 std
和 Boost
,那么我们为什么还需要另一个核心库呢?事实上,Folly 的目标不是取代任何库,而是补充它们。Folly 是为那些需要更高性能或尚未实现的情况而设计的。目前,Facebook 本身在其 数百万台服务器 上使用它,这些服务器支持超过 20 亿用户,并且还用于 Facebook 移动应用,根据 Google Play 的数据,这些应用在超过 10 亿台设备上使用。这证明了 Folly 项目的成熟度和可靠性。
在 CppCon 2016 版本中,演示文稿 “Facebook 中 std::string 的奇怪细节” 展示了 Andrei Alexandrescu 在实现 FBString 方面所做的工作,这是一个旨在提高效率、与 std::string
兼容的类,其速度比 string::find()
**快 30 倍**。
除了旨在实现高效率之外,Folly 还旨在易于使用,以加快新用户的集成和学习。例如,可以通过 Conv 简化字符串转换,或通过 Synchronized 简化互斥体同步,甚至可以使用 ProducerConsumerQueue 来同步多线程编程的队列。
光说不练假把式
为了说明 Folly 的用法,让我们用一个示例项目来验证一个 URI,使用 Futures、FBString、Executors 和 Format
#include <utility>
#include <iostream>
#include <folly/Format.h>
#include <folly/futures/Future.h>
#include <folly/executors/ThreadedExecutor.h>
#include <folly/Uri.h>
#include <folly/FBString.h>
static void print_uri(const folly::fbstring& address) {
const folly::Uri uri(address);
const auto authority = folly::format("The authority from {} is {}", uri.fbstr(), uri.authority());
std::cout << authority << std::endl;
}
int main() {
folly::ThreadedExecutor executor;
folly::Promise<folly::fbstring> promise;
folly::Future<folly::fbstring> future = promise.getSemiFuture().via(&executor);
folly::Future<folly::Unit> unit = std::move(future).thenValue(print_uri);
promise.setValue("https://conan.org.cn/");
std::move(unit).get();
return 0;
}
上面的代码应该在 future 回调执行后不久打印消息 “https://conan.org.cn 的 authority 为 conan.io”。让我们详细了解一下
static void print_uri(const folly::fbstring& address) {
const folly::Uri uri(address);
const auto authority = folly::format("The authority from {} is {}", uri.fbstr(), uri.authority());
std::cout << authority << std::endl;
}
这个小函数负责解析地址、验证地址是否为有效的 URI、格式化 URI 上存在的 authority 字符串,并通过标准输出显示。 FBString
类有 3 种存储策略
- 小字符串(<= 23 个字符)在原地存储,无需内存分配。
- 中等字符串(24 - 255 个字符)存储在 malloc 分配的内存中并急切复制。
- 大字符串(> 255 个字符)存储在 malloc 分配的内存中并延迟复制。
接收到的地址只有 17 个字符,因此它将存储在没有内存分配的情况下。 Uri
将在其构造函数中解析地址,为此将使用 Boost Regex。最后将使用快速而强大的 folly::format
进行格式化。
folly::Future<folly::fbstring> future = promise.getSemiFuture().via(&executor);
folly::Future<folly::Unit> unit = std::move(future).thenValue(print_uri);
promise.setValue("https://conan.org.cn/");
std::move(unit).get();
Future 不过是对异步计算结果的一种表示,该结果可能尚未可用。完成后,它将包含执行的操作的结果。Folly Future 能够通过 thenValue
和 thenTry
在完成之后执行回调。执行器指定工作将在哪里运行,因此,给定一个执行器,我们可以将 SemiFuture
转换为带有执行器的 Future
。最后,我们将要由回调函数使用值设置为并通过 get()
等待结果。
现在我们有了示例代码和构建描述,我们需要一个环境来构建项目,包括 Folly 库及其依赖项。
Folly 的依赖项
虽然 Folly 是 C++ 环境的一个优秀项目,但它具有复杂的依赖关系结构
此图可以使用 conan info 命令生成
$ conan info folly/2018.11.12.00@bincrafters/stable --graph index.html
如所述,Conan 列出了另外 11 个与 Folly 直接相关的项目,包括 Boost 库。现在您可以意识到准备使用 Folly 的环境的任务有多么困难和耗时。
该项目本身列出了如何在 Linux、Windows 和 OSX 平台上解决其依赖项。但是,在 Linux 上,必须使用发行版提供的版本,并且不总是想要的版本。在 Windows 上,仍然可以选择使用 Vcpkg,但是,您需要等待所有依赖项构建完成后才能编译任何示例代码。
Conan 来救援
Conan C++ 包管理器能够计算依赖关系图并解决依赖关系。为了解决此类依赖关系,必须创建一个小文件 conanfile.txt
来告诉 conan 获取 conan Folly 包并为我们方便起见生成一个 cmake 文件
[requires]
folly/2018.11.12.00@bincrafters/stable
[generators]
cmake
该文件显示了我们项目的要求,在本例中仅为 Folly 项目,由 Bincrafters 分发,版本为 2018.11.12.00,可在 Bintray 和 Conan 中心 上获得,后者在 conan-cli 中预先配置。由于我们使用 CMake 构建项目,因此我们需要告诉 Conan 运行其 cmake 生成器 以提供一个文件,其中包含所有必要的设置,以便能够导入 Folly。虽然我们在此项目中使用 cmake,但 Conan 还有其他几个 生成器,包括 QMake、Visual Studio、XCode 等。
Folly 列出的所有 11 个依赖项都将由 Conan 自动解决!
不幸的是,仅靠 CMake 无法解决 Folly 需要的所有额外依赖项,因此我们需要一起使用 Conan 和 CMake 来声明额外的包。让我们编写 CMakeLists.txt
cmake_minimum_required(VERSION 3.1.3)
project(folly_example CXX)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup(TARGETS)
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} CONAN_PKG::folly)
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 14)
函数 conan_basic_setup
将负责配置所有必要的设置,包括头文件和库文件的路径。 conanbuildinfo.cmake
由 Conan 生成,一旦配置的生成器类型为 cmake。Conan 生成的 CONAN_PKG::folly
目标拥有 Folly 项目,以及所有列为依赖项的库。
构建时间
现在 CMake 文件已更新,Conan 脚本已列出相应的依赖项,我们可以构建我们的示例
$ mkdir build && cd build
$ conan install ..
$ cmake .. -G "Visual Studio 15 Win64"
$ cmake --build . --config Release
conan install 命令负责读取 conanfile.txt
文件,根据默认配置文件(基于主机配置)下载和安装 Folly,并生成包含我们下一步所需的所有信息的 conanbuildinfo.cmake
。使用 CMake 的命令将负责生成构建文件,以及构建示例。
构建完成后,我们可以运行我们的示例项目
$ bin/folly_example
Callback Future: Hello World!
结论
C++ 世界拥有像 Folly 这样令人难以置信的项目来帮助解决现实世界的问题,但是,准备一个包含所有必要依赖项的环境可能是一项漫长而痛苦的任务。虽然 Folly 是您项目的优秀工具,但与 Boost 正则表达式等相关的 11 个项目的复杂性可以被视为避免使用它的不利因素。Folly 项目的案例证明了依赖项管理器和 Conan 等包对于现代 C++ 开发环境的重要性。
您是否有兴趣发表评论、提问或建议?请打开一个 问题!