《Pyflink》Flink集群安装,Python+Flink调研

Flink集群安装,Python+Flink调研

Flink集群部署

  1. 下载对应版本安装包:https://flink.apache.org/downloads.html

    实验环境为hadoop2.7, scala2.11 所以下载flink-1.7.1-bin-hadoop27-scala_2.11.tgz

  2. 配置conf/flink-conf.yaml

    jobmanager.rpc.address : master 节点
    jobmanager.heap.mb : JobManager可用的内存数量
    taskmanager.heap.mb : 每个TaskManager可以用内存数量
    taskmanager.numberOfTaskSlots : 每个机器可用的CPU数量
    parallelism.default : 集群中总的CPU数量
    taskmanager.tmp.dirs : 临时目录
    
  3. 配置conf/slaves

    slave1
    slave2
    

    点击查看更多配置项

  4. 把在master上配置好的,文件夹发送到各个worker节点上

    scp -r flink-1.7.1 hadoop@slavle1:~
    scp -r flink-1.7.1 hadoop@slavle2:~
    
  5. 启动/终止 Flink

    # 启动一个JobManager,并通过SSH连接列在slaves文件中的所有节点以便在每个节点上启动TaskManager
    flink-1.7.1/bin/start-cluster.sh
    # 停止flink集群,直接在master节点运行bin/stop-cluster.sh
    flink-1.7.1/bin/stop-cluster.sh
    

    启动后在web界面输入:master:8081 查看Web-UI

运行Python脚本

  • 以官网的一个示例进行测试,可以复制粘贴这些代码存储为wordcount.py并在本地运行。

  • wordcount.py

    from flink.plan.Environment import get_environment
    from flink.functions.GroupReduceFunction import GroupReduceFunctionclass Adder(GroupReduceFunction):def reduce(self, iterator, collector):count, word = iterator.next()count += sum([x[0] for x in iterator])collector.collect((count, word))
    # 1. 获取一个运行环境    
    env = get_environment() # 2. 加载/创建初始数据
    data = env.from_elements("Who's there?","I think I hear them. Stand, ho! Who's there?")# 3. 指定对这些数据的操作    
    data \.flat_map(lambda x, c: [(1, word) for word in x.lower().split()]) \.group_by(1) \.reduce_group(Adder(), combinable=True) \.output()# 4. 运行程序    
    env.execute(local=True) # 设置execute(local=True)强制程序在本机运行
    
  • 执行方法

    为了在Flink中运行计划任务,到Flink目录下,运行/bin文件夹下的pyflink.sh脚本。对于python2.7版本,运行pyflink2.sh;对于python3.4版本,运行pyflink3.sh。包含计划任务的脚本应当作为第一个输入参数,其后可添加一些另外的python包,最后,在“-”之后,输入其他附加参数。
    ./bin/pyflink<2/3>.sh <Script>[ <pathToPackage1>[ <pathToPackageX]][ - <param1>[ <paramX>]]

  • 针对上面的示例,在master-shell输入:
    flink-1.7.1/bin/pyflink.sh ./wordcount.py

  • vi flink-1.7.1/log/flink-hadoop-taskexecutor-0-slave1.out查看输出:

任务详解

  • 从示例程序可以看出,Flink程序看起来就像普通的python程序一样。每个程序都包含相同的基本组成部分:

    1. 获取一个运行环境
    2. 加载/创建初始数据
    3. 指定对这些数据的操作
    4. 指定计算结果的存放位置
    5. 运行程序
  • Environment(运行环境)是所有Flink程序的基础。通过调用Environment类中的一些静态方法来建立一个环境:

    get_environment()
    
  • 运行环境可通过多种读文件的方式来指定数据源。如果是简单的按行读取文本文件:

    env = get_environment()
    text = env.read_text("file:///path/to/file")
    

    这样,你就获得了可以进行操作(apply transformations)的数据集。关于数据源和输入格式的更多信息,请参考Data Sources

    一旦你获得了一个数据集DataSet,你就可以通过transformations来创建一个新的数据集,并把它写入到文件,再次transform,或者与其他数据集相结合。你可以通过对数据集调用自己个性化定制的函数来进行数据操作。例如,一个类似这样的数据映射操作:

    data.map(lambda x: x*2)
    

    这将会创建一个新的数据集,其中的每个数据都是原来数据集中的2倍。若要获取关于所有transformations的更多信息,及所有数据操作的列表,请参考Transformations。

  • 当需要将所获得的数据集写入到磁盘时,调用下面三种函数的其中一个即可。

      data.write_text("<file-path>", WriteMode=Constants.NO_OVERWRITE)write_csv("<file-path>", line_delimiter='\n', field_delimiter=',', write_mode=Constants.NO_OVERWRITE)output()
    

    其中,最后一种方法仅适用于在本机上进行开发/调试,它会将数据集的内容输出到标准输出。(请注意,当函数在集群上运行时,结果将会输出到整个集群节点的标准输出流,即输出到workers的.out文件。)前两种方法,能够将数据集写入到对应的文件中。关于写入到文件的更多信息,请参考Data Sinks。

    当设计好了程序之后,你需要在环境中执行execute命令来运行程序。可以选择在本机运行,也可以提交到集群运行,这取决于Flink的创建方式。你可以通过设置execute(local=True)强制程序在本机运行。

创建项目

  • 除了搭建好Flink运行环境,就无需进行其他准备工作了。Python包可以从你的Flink版本对应的/resource文件夹找到。在执行工作任务时,Flink 包,plan包和optional包均可以通过HDFS自动分发。

    Python API官方已经在安装了Python2.7或3.4的Linux/Windows系统上测试过。本次我是在安装了Python3.6的Linux环境进行测试。

    默认情况下,Flink通过调用”python”或”python3″来启动python进程,这取决于使用了哪种启动脚本。通过在 flink-conf.yaml 中设置 “python.binary.python[2/3]”对应的值,来设定你所需要的启动方式。

惰性评价

  • 所有的Flink程序都是延迟执行的。当程序的主函数执行时,数据的载入和操作并没有在当时发生。与此相反,每一个被创建出来的操作都被加入到程序的计划中。当程序环境中的某个对象调用了execute()函数时,这些操作才会被真正的执行。不论该程序是在本地运行还是集群上运行。

    延迟求值能够让你建立复杂的程序,并在Flink上以一个整体的计划单元来运行。

数据变换

  • 数据变换(Data transformations)可以将一个或多个数据集映射为一个新的数据集。程序能够将多种变换结合到一起来进行复杂的整合变换。

该小节将概述各种可以实现的数据变换。transformations documentation数据变换文档中,有关于所有数据变换和示例的全面介绍。

  1. Map:输入一个元素,输出一个元素

    data.map(lambda x: x * 2)
    
  2. FlatMap:输入一个元素,输出0,1,或多个元素

    data.flat_map(
    lambda x,c: [(1,word) for word in line.lower().split() for line 
    in x])
    
  3. MapPartition:通过一次函数调用实现并行的分割操作。该函数将分割变换作为一个”迭代器”,并且能够产生任意数量的输出值。每次分割变换的元素数量取决于变换的并行性和之前的操作结果。

    data.map_partition(lambda x,c: [value * 2 for value in x])
    
  4. Filter:对每一个元素,计算一个布尔表达式的值,保留函数计算结果为true的元素。

    data.filter(lambda x: x > 1000)
    
  5. Reduce:通过不断的将两个元素组合为一个,来将一组元素结合为一个单一的元素。这种缩减变换可以应用于整个数据集,也可以应用于已分组的数据集。

    data.reduce(lambda x,y : x + y)
    
  6. ReduceGroup:将一组元素缩减为1个或多个元素。缩减分组变换可以被应用于一个完整的数据集,或者一个分组数据集。

    lass Adder(GroupReduceFunction):
    def reduce(self, iterator, collector):count, word = iterator.next()count += sum([x[0] for x in iterator)      collector.collect((count, word))data.reduce_group(Adder())
    
  7. Aggregate:对一个数据集包含所有元组的一个域,或者数据集的每个数据组,执行某项built-in操作(求和,求最小值,求最大值)。聚集变换可以被应用于一个完整的数据集,或者一个分组数据集。

    # This code finds the sum of all of the values in the first field
    and the maximum of all of the values in the second field
    data.aggregate(Aggregation.Sum, 0).and_agg(Aggregation.Max, 1)# min(), max(), and sum() syntactic sugar functions are also available
    data.sum(0).and_agg(Aggregation.Max, 1)
    
  8. Join:对两个数据集进行联合变换,将得到一个新的数据集,其中包含在两个数据集中拥有相等关键字的所有元素对。也可通过JoinFunction来把成对的元素变为单独的元素。关于join keys的更多信息请查看 keys

    # In this case tuple fields are used as keys.
    # "0" is the join field on the first tuple
    # "1" is the join field on the second tuple.
    result = input1.join(input2).where(0).equal_to(1)
    
  9. CoGroup:是Reduce变换在二维空间的一个变体。将来自一个或多个域的数据加入数据组。变换函数transformation function将被每一对数据组调用。关于定义coGroup keys的更多信息,请查看 keys 。

    data1.co_group(data2).where(0).equal_to(1)
    
  10. Cross:计算两个输入数据集的笛卡尔乘积(向量叉乘),得到所有元素对。也可通过CrossFunction实现将一对元素转变为一个单独的元素。

    result = data1.cross(data2)
    
  11. Union:将两个数据集进行合并。

    data.union(data2)
    
  12. ZipWithIndex:为数据组中的元素逐个分配连续的索引。了解更多信息,请参考 【Zip Elements Guide】(zip_elements_guide.html#zip-with-a-dense-index).

    data.zip_with_index()
    

指定keys

  • 一些变换(例如Join和CoGroup),需要在进行变换前,为作为输入参数的数据集指定一个关键字,而另一些变换(例如Reduce和GroupReduce),则允许在变换操作之前,对数据集根据某个关键字进行分组。

    数据集可通过如下方式分组

    reduced = data \
    .group_by(<define key here>) \
    .reduce_group(<do something>)
    

    Flink中的数据模型并不是基于键-值对。你无需将数据集整理为keys和values的形式。键是”虚拟的”:它们被定义为在真实数据之上,引导分组操作的函数。

为元组定义keys

  • 最简单的情形是对一个数据集中的元组按照一个或多个域进行分组:

    grouped = data \
    .group_by(0) \
    .reduce(/*do something*/)
    

    数据集中的元组被按照第一个域分组。对于接下来的group-reduce函数,输入的数据组中,每个元组的第一个域都有相同的值。

    grouped = data \
    .group_by(0,1) \
    .reduce(/*do something*/)
    

    在上面的例子中,数据集的分组基于第一个和第二个域形成的复合关键字,因此,reduce函数输入数据组中,每个元组两个域的值均相同。
    关于嵌套元组需要注意:如果你有一个使用了嵌套元组的数据集,指定group_by()操作,系统将把整个元组作为关键字使用。

向Flink传递函数

  • 一些特定的操作需要采用用户自定义的函数,因此它们都接受lambda表达式和rich functions作为输入参数。

    data.filter(lambda x: x > 5)class Filter(FilterFunction):def filter(self, value):return value > 5data.filter(Filter())
    

Rich functions可以将函数作为输入参数,允许使用broadcast-variables(广播变量),能够由init()函数参数化,是复杂函数的一个可考虑的实现方式。它们也是在reduce操作中,定义一个可选的combine function的唯一方式。
Lambda表达式可以让函数在一行代码上实现,非常便捷。需要注意的是,如果某个操作会返回多个数值,则其使用的lambda表达式应当返回一个迭代器。(所有函数将接收一个collector输入 参数)。

数据类型

  • Flink的Python API目前仅支持python中的基本数据类型(int,float,bool,string)以及byte arrays。
    运行环境对数据类型的支持,包括序列化器serializer,反序列化器deserializer,以及自定义类型的类。

    class MyObj(object):def __init__(self, i):self.value = iclass MySerializer(object):def serialize(self, value):return struct.pack(">i", value.value)class MyDeserializer(object):def _deserialize(self, read):i = struct.unpack(">i", read(4))[0]return MyObj(i)env.register_custom_type(MyObj, MySerializer(), MyDeserializer())
    

    Tuples/Lists

    可以使用元组(或列表)来表示复杂类型。Python中的元组可以转换为Flink中的Tuple类型,它们包含数量固定的不同类型的域(最多25个)。每个域的元组可以是基本数据类型,也可以是其他的元组类型,从而形成嵌套元组类型。

    
    word_counts = env.from_elements(("hello", 1), ("world",2))counts = word_counts.map(lambda x: x[1])
    

    当进行一些要求指定关键字的操作时,例如对数据记录进行分组或配对。通过设定关键字,可以非常便捷地指定元组中各个域的位置。你可以指定多个位置,从而实现复合关键字(更多信息,查阅Section Data Transformations)。

    wordCounts \
    .group_by(0) \
    .reduce(MyReduceFunction())
    

数据源

  • 数据源创建了初始的数据集,包括来自文件,以及来自数据接口/集合两种方式。

    1. 基于文件的:

      read_text(path) – 按行读取文件,并将每一行以String形式返回。
      read_csv(path,type) – 解析以逗号(或其他字符)划分数据域的文件。
      返回一个包含若干元组的数据集。支持基本的java数据类型作为字段类型。

    2. 基于数据集合的:

      from_elements(*args) – 基于一系列数据创建一个数据集,包含所有元素。
      generate_sequence(from, to) – 按照指定的间隔,生成一系列数据。

  • Examples

    env  = get_environment\# read text file from local files system
    localLiens = env.read_text("file:#/path/to/my/textfile")\# read text file from a HDFS running at nnHost:nnPort
    hdfsLines = env.read_text("hdfs://nnHost:nnPort/path/to/my/textfile")\# read a CSV file with three fields, schema defined using constants defined in flink.plan.Constants
    csvInput = env.read_csv("hdfs:///the/CSV/file", (INT, STRING, DOUBLE))\# create a set from some given elements
    values = env.from_elements("Foo", "bar", "foobar", "fubar")\# generate a number sequence
    numbers = env.generate_sequence(1, 10000000)
    

数据接收器

  • 数据接收器可以接受DataSet,并用来存储和返回它们:

    1. write_text() –按行以String形式写入数据。可通过对每个数据项调用str()函数获取String。

    2. write_csv(…) – 将元组写入逗号分隔数值文件。行数和数据字段均可配置。每个字段的值可通过对数据项调用str()方法得到。

    3. output() – 在标准输出上打印每个数据项的str()字符串。
      一个数据集可以同时作为多个操作的输入数据。程序可以在写入或打印一个数据集的同时,对其进行其他的变换操作。

  • 标准数据池相关方法示例如下:

    write DataSet to a file on the local file system
    textData.write_text("file:///my/result/on/localFS")write DataSet to a file on a HDFS with a namenode running at nnHost:nnPort
    textData.write_text("hdfs://nnHost:nnPort/my/result/on/localFS")write DataSet to a file and overwrite the file if it exists
    textData.write_text("file:///my/result/on/localFS", WriteMode.OVERWRITE)tuples as lines with pipe as the separator "a|b|c"
    values.write_csv("file:///path/to/the/result/file", line_delimiter="\n", field_delimiter="|")this writes tuples in the text formatting "(a, b, c)", rather than as CSV lines
    values.write_text("file:///path/to/the/result/file")
    

广播变量

  • 使用广播变量,能够在使用普通输入参数的基础上,使得一个数据集同时被多个并行的操作所使用。这对于实现辅助数据集,或者是基于数据的参数化法非常有用。这样,数据集就可以以集合的形式被访问。

  • 注册广播变量:广播数据集可通过调用with_broadcast_set(DataSet,String)函数,按照名字注册广播变量。

  • 访问广播变量:通过对调用self.context.get_broadcast_variable(String)可获取广播变量。

    class MapperBcv(MapFunction):
    def map(self, value):factor = self.context.get_broadcast_variable("bcv")[0][0]return value * factor# 1. The DataSet to be broadcasted
    toBroadcast = env.from_elements(1, 2, 3)
    data = env.from_elements("a", "b")# 2. Broadcast the DataSet
    data.map(MapperBcv()).with_broadcast_set("bcv", toBroadcast)
  • 确保在进行广播变量的注册和访问时,应当采用相同的名字(示例中的”bcv”)。

    注意:由于广播变量的内容被保存在每个节点的内部存储中,不适合包含过多内容。一些简单的参数,例如标量值,可简单地通过参数化rich function来实现。

并行执行

  • 该章节将描述如何在Flink中配置程序的并行执行。一个Flink程序可以包含多个任务(操作,数据源和数据池)。一个任务可以被划分为多个可并行运行的部分,每个部分处理输入数据的一个子集。并行运行的实例数量被称作它的并行性或并行度degree of parallelism (DOP)。
    在Flink中可以为任务指定不同等级的并行度。

运行环境级

  • Flink程序可在一个运行环境execution environment的上下文中运行。一个运行环境为其中运行的所有操作,数据源和数据池定义了一个默认的并行度。运行环境的并行度可通过对某个操作的并行度进行配置来修改。

    一个运行环境的并行度可通过调用set_parallelism()方法来指定。例如,为了将WordCount示例程序中的所有操作,数据源和数据池的并行度设置为3,可以通过如下方式设置运行环境的默认并行度。

    env = get_environment()
    env.set_parallelism(3)text.flat_map(lambda x,c: x.lower().split()) \.group_by(1) \.reduce_group(Adder(), combinable=True) \.output()env.execute()
    

系统级

  • 通过设置位于./conf/flink-conf.yaml.文件的parallelism.default属性,改变系统级的默认并行度,可设置所有运行环境的默认并行度。具体细节可查阅Configuration文档。

执行方法

  • 为了在Flink中运行计划任务,到Flink目录下,运行/bin文件夹下的pyflink.sh脚本。对于python2.7版本,运行pyflink2.sh;对于python3.4版本,运行pyflink3.sh。包含计划任务的脚本应当作为第一个输入参数,其后可添加一些另外的python包,最后,在“-”之后,输入其他附加参数。

    ./bin/pyflink<2/3>.sh <Script>[ <pathToPackage1>[ <pathToPackageX]][ - <param1>[ <paramX>]]
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/292897.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

项目手札2---关于分页显示时地址栏的风格

在控制器里&#xff0c;用RequestMapping("")时我们可能用RESTFUL风格的来映射&#xff0c;也有可能是用其他的方式&#xff0c;用或不用RESTFUL风格在分页显示时的地址栏里有些不同。首先来看不用RESTFUL时地址栏的样子&#xff1a; <li><a href"show…

shell基础二

前面已经讲到&#xff0c;变量名只能包含数字、字母和下划线&#xff0c;因为某些包含其他字符的变量有特殊含义&#xff0c;这样的变量被称为特殊变量。例如&#xff0c;$ 表示当前Shell进程的ID&#xff0c;即pid&#xff0c;看下面的代码&#xff1a; $echo $$ 运行结果 29…

hdu 4539(状压dp)

题目链接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid4539 思路&#xff1a;跟poj1185简直就是如出一辙&#xff01; 1 #include<iostream>2 #include<cstdio>3 #include<cstring>4 #include<algorithm>5 using namespace std;6 7 int row…

万字长文入门 Redis 命令、事务、锁、订阅、性能测试

Redis 基本数据类型Redis 中&#xff0c;常用的数据类型有以下几种&#xff1a;String&#xff1a;字符串类型&#xff0c;二进制安全字符串&#xff1b;Hash&#xff1a;哈希表&#xff1b;List 列表&#xff1a;链表结构&#xff0c;按照插入顺序排序的字符串元素的集合&…

postgresql 查看page, index, tuple 详细信息

下面的内容需要理解postgres术语 page, tuple, regclass, relname. sql command 需要用到 pgstattuple,pageinspect extension.Setup Extension create extension pgstatuplecreate extension pageinspect 查询page, index 详细信息 show how many pages in one tableselect pg…

python读写文件错误_Python读取csv文件错误解决方法

如果累了就拥抱我取暖 ——侃爷 今天这篇推文很简单&#xff0c;就是给大家总结一下我今天用pandas读取csv文件遇到的坑。 一直处理csv文件都是用pandas的read_csv函数读取csv文件之后处理&#xff0c;都没碰到过什么问题。But&#xff0c;But今天帮朋友处理csv文件时&#xff…

基于应用日志的扫描器检测实践

基于应用日志的扫描器检测实践 在网络上搜索web扫描器时&#xff0c;各类扫描器工具、扫描攻略玲琅满目&#xff0c;但对扫描器检测方法的内容却少之又少。因此&#xff0c;本文对各类web扫描特特征进行了梳理和总结&#xff0c;并结合苏宁应用防火墙&#xff08;SNWAF&#x…

shell基础三

如果表达式中包含特殊字符&#xff0c;Shell 将会进行替换。例如&#xff0c;在双引号中使用变量就是一种替换&#xff0c;转义字符也是一种替换。举个例子&#xff1a; #!/bin/basha10echo -e "Value of a is $a \n" 运行结果&#xff1a; Value of a is 10 这里 …

将一个压缩文件分成多个压缩文件;RAR文件分卷

有时候需要上传压缩文件&#xff0c;但是限制了单个文件的大小&#xff0c;那我们怎么才能将一个比较大的压缩文件分割成多个压缩文件&#xff0c;从而符合要求的进行文件的上传呢&#xff1f;这里小编告诉你一个技巧。 工具/原料 电脑 winrar&#xff08;一般电脑都自带了&…

定义命令别名(alias)

Linux之alias:1.查看当前别名&#xff1a;alias# alias alias cpcp -i alias l.ls -d .* --colortty alias llls -l --colortty alias lsls --colortty alias mvmv -i alias rmrm -i alias whichalias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde 2.设…

python画相关性可视化图_Python可视化很简单,一文教你绘制饼图、极线图和气泡图...

matplotlib库作为Python数据化可视化的最经典和最常用库&#xff0c;掌握了它就相当于学会了Python的数据化可视化&#xff0c;上次呢&#xff0c;已经和大家聊了关于柱状图、条形图和直方图相关的东东&#xff0c;相信大家已经掌握了哈&#xff0c;那今天呢&#xff0c;咱们再…

图像处理技术(二)滤波去噪

在图像处理领域中&#xff0c;在真正的应用过程前&#xff0c;通常需要对图像进行预先处理&#xff0c;达到去除干扰项的目的。滤波去噪就是其中的一项图像预处理工作。在.NET下常用OpenCV进行图像处理工作,常用的.NET下的OpenCV库有Emgu CV和OpenCVSharp。EmguCV是.NET平台下对…

iOS开发之Runtime关联属性

2019独角兽企业重金招聘Python工程师标准>>> 首先&#xff0c;推荐给大家一个非常好用的一个网站&#xff1a; 非盈利无广告开发者专用网址导航&#xff1a;http://www.dev666.com/ API介绍 我们先看看Runtime提供的关联API&#xff0c;只有这三个API&#xff0c;使…

shell基础四

Bash 支持很多运算符&#xff0c;包括算数运算符、关系运算符、布尔运算符、字符串运算符和文件测试运算符。原生bash不支持简单的数学运算&#xff0c;但是可以通过其他命令来实现&#xff0c;例如 awk 和 expr&#xff0c;expr 最常用。expr 是一款表达式计算工具&#xff0c…

DecisionTree决策树算法及参数详解+实例+graphviz生成决策树

DecisionTree决策树大全 原文&#xff1a;http://ihoge.cn/2018/DecisionTree.html 利用信息墒判定先对那个特征进行分裂 信息墒是衡量信息不确定性的指标&#xff0c;信息墒公式&#xff1a; H(X)−∑x∈XP(x)log2P(x)其中P(x)表示事件x出现的概率。回到决策树的构建问题上…

穿皮裤放屁,裤子会鼓吗?真相看这里!

1 拉莫斯&#xff1a;没事儿&#xff0c;打今儿起我管你叫哥&#xff0c;你管我叫爸&#xff0c;咱俩各论各的。▼2 妈妈都是为了你好▼3 秃头女孩最后的倔强▼4 新浪OS&#xff1a;呼~太紧张了&#xff0c;放松下▼5 这什么鬼玩意儿&#xff1f;▼6 这到底是爱老婆&…

公布一个软件,轻新视频录播程序,H264/AAC录制视音频,保存FLV,支持RTMP直播...

已经上传到CSDN&#xff0c;下载地址&#xff1a;http://download.csdn.net/detail/avsuper/7421647&#xff0c;不要钱滴&#xff0c;嘿嘿。。。 本程序能够把摄像头视频和麦克风音频&#xff0c;录制为FLV文件。 视频压缩採用H.264编码&#xff0c;音频压缩採用AAC编码&#…

linux共享库及/etc/ld.so.conf文件的应用

Linux 共享库 Linux 系统上有两类根本不同的 Linux 可执行程序。第一类是静态链接的可执行程序。静态可执行程序包含执行所需的所有函数 —换句话说&#xff0c;它们是“完整的”。因为这一原因&#xff0c;静态可执行程序不依赖任何外部库就可以运行。  第二类是动态链接的…