首页 文章 精选 留言 我的

精选列表

搜索[快速入门],共10000篇文章
优秀的个人博客,低调大师

使用 Jupiter Notebook 运行 Delta Lake 入门教程

本文的例子来自 Delta Lake 官方教程。因为官方教程是基于商业软件 Databricks Community Edition 构建,虽然教程中使用的软件特性都是开源 Delta Lake 版本所具备的,但是考虑到国内的网络环境,注册和使用 Databricks Community Edition 门槛较高。所以本文尝试基于开源的 Jupiter Notebook 重新构建这个教程。 准备一个环境安装 Spark 和 jupyter 本文基于 Linux 构建开发环境,同时使用的软件比如 conda、jupyter以及 pyspark 等都可以在 Windows 和 MacOS 上找到,理论上来说也完全可以在这两个系统上完成此教程。 假设系统已经安装 anaconda 或 miniconda,我们使用 conda 来构建开发环境,可以非常方便的安装 pyspark 和 jupyter notebook conda create --name spark conda activate spark conda install pyspark conda install -c conda-forge jupyterlab 环境变量设置 我们在设置一些环境变量之后,就可以使用 pyspark 命令来创建 jupyter notebook 服务 export SPARK_HOME=$HOME/miniconda3/envs/spark/lib/python3.7/site-packages/pyspark export PYSPARK_DRIVER_PYTHON=jupyter export PYSPARK_DRIVER_PYTHON_OPTS='notebook' 启动服务(注意这里的参数里指定了 Delta Lake 的 package,Spark 会帮忙自动下载依赖): pyspark --packages io.delta:delta-core_2.11:0.5.0 接下去所有代码在 notebook 里运行 下载需要 parquet 文件 %%bash rm -fr /tmp/delta_demo mkdir -p /tmp/delta_demo/loans/ wget -O /tmp/delta_demo/loans/SAISEU19-loan-risks.snappy.parquet https://pages.databricks.com/rs/094-YMS-629/images/SAISEU19-loan-risks.snappy.parquet ls -al /tmp/delta_demo/loans/ Delta Lake的批流处理 在这里我们进入正题,开始介绍 Delta Lake 的批流处理能力。 首先,我们通过批处理的形式创建一张 Delta Lake 表,数据来自前面我们下载的 parquet 文件,可以和方便的把一张 parquet 表转换为 Delta Lake 表: import os import shutil from pyspark.sql.functions import * delta_path = "/tmp/delta_demo/loans_delta" # Delete a new delta table with the parquet file if os.path.exists(delta_path): print("Deleting path " + delta_path) shutil.rmtree(delta_path) # Create a new delta table with the parquet file spark.read.format("parquet").load("/tmp/delta_demo/loans") \ .write.format("delta").save(delta_path) print("Created a Delta table at " + delta_path) 我来查一下这张表,数据量是否正确: # Create a view on the table called loans_delta spark.read.format("delta").load(delta_path).createOrReplaceTempView("loans_delta") print("Defined view 'loans_delta'") spark.sql("select count(*) from loans_delta").show() Defined view 'loans_delta' +--------+ |count(1)| +--------+ | 14705| +--------+ 接下去我们会使用Spark Streaming流式写入这张 Delta Lake 表,同时展示 Delta Lake 的 Schema enforcement 能力(本文省略了流式写 Parquet 表的演示部分,那部分指出了 parquet 文件的不足,比如无法强制指定 Schema ) import random from pyspark.sql.functions import * from pyspark.sql.types import * def random_checkpoint_dir(): return "/tmp/delta_demo/chkpt/%s" % str(random.randint(0, 10000)) # User-defined function to generate random state states = ["CA", "TX", "NY", "IA"] @udf(returnType=StringType()) def random_state(): return str(random.choice(states)) # Generate a stream of randomly generated load data and append to the delta table def generate_and_append_data_stream_fixed(table_format, table_path): stream_data = spark.readStream.format("rate").option("rowsPerSecond", 50).load() \ .withColumn("loan_id", 10000 + col("value")) \ .withColumn("funded_amnt", (rand() * 5000 + 5000).cast("integer")) \ .withColumn("paid_amnt", col("funded_amnt") - (rand() * 2000)) \ .withColumn("addr_state", random_state()) \ .select("loan_id", "funded_amnt", "paid_amnt", "addr_state") # *********** FIXED THE SCHEMA OF THE GENERATED DATA ************* query = stream_data.writeStream \ .format(table_format) \ .option("checkpointLocation", random_checkpoint_dir()) \ .trigger(processingTime="10 seconds") \ .start(table_path) return query 启动两个流式作业: stream_query_1 = generate_and_append_data_stream_fixed(table_format = "delta", table_path = delta_path) stream_query_2 = generate_and_append_data_stream_fixed(table_format = "delta", table_path = delta_path) 因为 Delta Lake 的乐观锁机制,多个流可以同时写入一张表,并保证数据的完整性。 通过批处理的方式来查询一下当前表中的数据量,我们发现有数据被插入了: spark.sql("select count(*) from loans_delta").show() +--------+ |count(1)| +--------+ | 17605| +--------+ 接下去我们停止所有流的写入,接下去会展示 Delta Lake 的其他特性 # Function to stop all streaming queries def stop_all_streams(): # Stop all the streams print("Stopping all streams") for s in spark.streams.active: s.stop() print("Stopped all streams") print("Deleting checkpoints") shutil.rmtree("/tmp/delta_demo/chkpt/", True) print("Deleted checkpoints") stop_all_streams() Schema evolution(Schema演化) Delta Lake 支持Schema演化,也就是说我们可以增加或改变表字段。接下去的批处理 SQL 会新增加一些数据,同时这些数据比之前的多了一个“closed”字段。我们将新的 DF 配置参数 mergeSchema 为 true 来显示指明 Delta Lake 表 Schema 的演化: cols = ['loan_id', 'funded_amnt', 'paid_amnt', 'addr_state', 'closed'] items = [ (1111111, 1000, 1000.0, 'TX', True), (2222222, 2000, 0.0, 'CA', False) ] loan_updates = spark.createDataFrame(items, cols) \ .withColumn("funded_amnt", col("funded_amnt").cast("int")) loan_updates.write.format("delta") \ .mode("append") \ .option("mergeSchema", "true") \ .save(delta_path) 来看一下插入新数据之后的表内容,新增加了 closed 字段,之前的老数据行这个字段默认为 null。 spark.read.format("delta").load(delta_path).show() +-------+-----------+---------+----------+------+ |loan_id|funded_amnt|paid_amnt|addr_state|closed| +-------+-----------+---------+----------+------+ | 0| 1000| 182.22| CA| null| | 1| 1000| 361.19| WA| null| | 2| 1000| 176.26| TX| null| | 3| 1000| 1000.0| OK| null| | 4| 1000| 249.98| PA| null| | 5| 1000| 408.6| CA| null| | 6| 1000| 1000.0| MD| null| | 7| 1000| 168.81| OH| null| | 8| 1000| 193.64| TX| null| | 9| 1000| 218.83| CT| null| | 10| 1000| 322.37| NJ| null| | 11| 1000| 400.61| NY| null| | 12| 1000| 1000.0| FL| null| | 13| 1000| 165.88| NJ| null| | 14| 1000| 190.6| TX| null| | 15| 1000| 1000.0| OH| null| | 16| 1000| 213.72| MI| null| | 17| 1000| 188.89| MI| null| | 18| 1000| 237.41| CA| null| | 19| 1000| 203.85| CA| null| +-------+-----------+---------+----------+------+ only showing top 20 rows 新的数据行具有 closed 字段: spark.read.format("delta").load(delta_path).filter(col("closed") == True).show() +-------+-----------+---------+----------+------+ |loan_id|funded_amnt|paid_amnt|addr_state|closed| +-------+-----------+---------+----------+------+ |1111111| 1000| 1000.0| TX| true| +-------+-----------+---------+----------+------+ Delta Lake 表的删除操作 除了常规的插入操作,Delta Lake 还支持 update 和 delete 等功能,可以更新表格内容。下面展示删除操作,我们希望删除表格中贷款已经被完全还清的记录。下面几条命令可以简单和清晰的展示删除过程。 首先,我们看看符合条件的记录有多少条: spark.sql("SELECT COUNT(*) FROM loans_delta WHERE funded_amnt = paid_amnt").show() +--------+ |count(1)| +--------+ | 5134| +--------+ 然后,我们执行一个 delete 命令: from delta.tables import * deltaTable = DeltaTable.forPath(spark, delta_path) deltaTable.delete("funded_amnt = paid_amnt") 最后,我们看一下删除后的结果,发现符合条件的记录都已被删除: spark.sql("SELECT COUNT(*) FROM loans_delta WHERE funded_amnt = paid_amnt").show() +--------+ |count(1)| +--------+ | 0| +--------+ 版本历史和回溯 Delta Lake 还具有很强大历史版本记录和回溯功能。history()方法清晰的展示了刚才那张表的修改记录,包括最后一次 Delete 操作。 deltaTable.history().show() +-------+-------------------+------+--------+----------------+--------------------+----+--------+---------+-----------+--------------+-------------+ |version| timestamp|userId|userName| operation| operationParameters| job|notebook|clusterId|readVersion|isolationLevel|isBlindAppend| +-------+-------------------+------+--------+----------------+--------------------+----+--------+---------+-----------+--------------+-------------+ | 10|2020-02-22 22:14:06| null| null| DELETE|[predicate -> ["(...|null| null| null| 9| null| false| | 9|2020-02-22 22:13:57| null| null| WRITE|[mode -> Append, ...|null| null| null| 8| null| true| | 8|2020-02-22 22:13:52| null| null|STREAMING UPDATE|[outputMode -> Ap...|null| null| null| 6| null| true| | 7|2020-02-22 22:13:50| null| null|STREAMING UPDATE|[outputMode -> Ap...|null| null| null| 6| null| true| | 6|2020-02-22 22:13:42| null| null|STREAMING UPDATE|[outputMode -> Ap...|null| null| null| 4| null| true| | 5|2020-02-22 22:13:40| null| null|STREAMING UPDATE|[outputMode -> Ap...|null| null| null| 4| null| true| | 4|2020-02-22 22:13:32| null| null|STREAMING UPDATE|[outputMode -> Ap...|null| null| null| 2| null| true| | 3|2020-02-22 22:13:30| null| null|STREAMING UPDATE|[outputMode -> Ap...|null| null| null| 2| null| true| | 2|2020-02-22 22:13:22| null| null|STREAMING UPDATE|[outputMode -> Ap...|null| null| null| 1| null| true| | 1|2020-02-22 22:13:20| null| null|STREAMING UPDATE|[outputMode -> Ap...|null| null| null| 0| null| true| | 0|2020-02-22 22:13:18| null| null| WRITE|[mode -> ErrorIfE...|null| null| null| null| null| true| +-------+-------------------+------+--------+----------------+--------------------+----+--------+---------+-----------+--------------+-------------+ 如果我们希望看一下刚才删除操作前的数据表状态,可以很方便的回溯到前一个快照点,并进行再次查询(我们可以看到被删除的记录又出现了)。 previousVersion = deltaTable.history(1).select("version").collect()[0][0] - 1 spark.read.format("delta") \ .option("versionAsOf", previousVersion) \ .load(delta_path) \ .createOrReplaceTempView("loans_delta_pre_delete") \ spark.sql("SELECT COUNT(*) FROM loans_delta_pre_delete WHERE funded_amnt = paid_amnt").show() +--------+ |count(1)| +--------+ | 5134| +--------+ 结论 本文通过 jupyter notebook 工具演示了 Delta Lake 的官方教程,你可以在本文末尾下载到完整的 notebook 文件。

优秀的个人博客,低调大师

使用 Jupyter Notebook 运行 Delta Lake 入门教程

本文的例子来自 Delta Lake 官方教程。因为官方教程是基于商业软件 Databricks Community Edition 构建,虽然教程中使用的软件特性都是开源 Delta Lake 版本所具备的,但是考虑到国内的网络环境,注册和使用 Databricks Community Edition 门槛较高。所以本文尝试基于开源的 Jupiter Notebook 重新构建这个教程。 准备一个环境安装 Spark 和 jupyter 本文基于 Linux 构建开发环境,同时使用的软件比如 conda、jupyter以及 pyspark 等都可以在 Windows 和 MacOS 上找到,理论上来说也完全可以在这两个系统上完成此教程。 假设系统已经安装 anaconda 或 miniconda,我们使用 conda 来构建开发环境,可以非常方便的安装 pyspark 和 jupyter notebook conda create --name spark conda activate spark conda install pyspark conda install -c conda-forge jupyterlab 环境变量设置 我们在设置一些环境变量之后,就可以使用 pyspark 命令来创建 jupyter notebook 服务 export SPARK_HOME=$HOME/miniconda3/envs/spark/lib/python3.7/site-packages/pyspark export PYSPARK_DRIVER_PYTHON=jupyter export PYSPARK_DRIVER_PYTHON_OPTS='notebook' 启动服务(注意这里的参数里指定了 Delta Lake 的 package,Spark 会帮忙自动下载依赖): pyspark --packages io.delta:delta-core_2.11:0.5.0 接下去所有代码在 notebook 里运行 下载需要 parquet 文件 %%bash rm -fr /tmp/delta_demo mkdir -p /tmp/delta_demo/loans/ wget -O /tmp/delta_demo/loans/SAISEU19-loan-risks.snappy.parquet https://pages.databricks.com/rs/094-YMS-629/images/SAISEU19-loan-risks.snappy.parquet ls -al /tmp/delta_demo/loans/ Delta Lake的批流处理 在这里我们进入正题,开始介绍 Delta Lake 的批流处理能力。 首先,我们通过批处理的形式创建一张 Delta Lake 表,数据来自前面我们下载的 parquet 文件,可以和方便的把一张 parquet 表转换为 Delta Lake 表: import os import shutil from pyspark.sql.functions import * delta_path = "/tmp/delta_demo/loans_delta" # Delete a new delta table with the parquet file if os.path.exists(delta_path): print("Deleting path " + delta_path) shutil.rmtree(delta_path) # Create a new delta table with the parquet file spark.read.format("parquet").load("/tmp/delta_demo/loans") \ .write.format("delta").save(delta_path) print("Created a Delta table at " + delta_path) 我来查一下这张表,数据量是否正确: # Create a view on the table called loans_delta spark.read.format("delta").load(delta_path).createOrReplaceTempView("loans_delta") print("Defined view 'loans_delta'") spark.sql("select count(*) from loans_delta").show() Defined view 'loans_delta' +--------+ |count(1)| +--------+ | 14705| +--------+ 接下去我们会使用Spark Streaming流式写入这张 Delta Lake 表,同时展示 Delta Lake 的 Schema enforcement 能力(本文省略了流式写 Parquet 表的演示部分,那部分指出了 parquet 文件的不足,比如无法强制指定 Schema ) import random from pyspark.sql.functions import * from pyspark.sql.types import * def random_checkpoint_dir(): return "/tmp/delta_demo/chkpt/%s" % str(random.randint(0, 10000)) # User-defined function to generate random state states = ["CA", "TX", "NY", "IA"] @udf(returnType=StringType()) def random_state(): return str(random.choice(states)) # Generate a stream of randomly generated load data and append to the delta table def generate_and_append_data_stream_fixed(table_format, table_path): stream_data = spark.readStream.format("rate").option("rowsPerSecond", 50).load() \ .withColumn("loan_id", 10000 + col("value")) \ .withColumn("funded_amnt", (rand() * 5000 + 5000).cast("integer")) \ .withColumn("paid_amnt", col("funded_amnt") - (rand() * 2000)) \ .withColumn("addr_state", random_state()) \ .select("loan_id", "funded_amnt", "paid_amnt", "addr_state") # *********** FIXED THE SCHEMA OF THE GENERATED DATA ************* query = stream_data.writeStream \ .format(table_format) \ .option("checkpointLocation", random_checkpoint_dir()) \ .trigger(processingTime="10 seconds") \ .start(table_path) return query 启动两个流式作业: stream_query_1 = generate_and_append_data_stream_fixed(table_format = "delta", table_path = delta_path) stream_query_2 = generate_and_append_data_stream_fixed(table_format = "delta", table_path = delta_path) 因为 Delta Lake 的乐观锁机制,多个流可以同时写入一张表,并保证数据的完整性。 通过批处理的方式来查询一下当前表中的数据量,我们发现有数据被插入了: spark.sql("select count(*) from loans_delta").show() +--------+ |count(1)| +--------+ | 17605| +--------+ 接下去我们停止所有流的写入,接下去会展示 Delta Lake 的其他特性 # Function to stop all streaming queries def stop_all_streams(): # Stop all the streams print("Stopping all streams") for s in spark.streams.active: s.stop() print("Stopped all streams") print("Deleting checkpoints") shutil.rmtree("/tmp/delta_demo/chkpt/", True) print("Deleted checkpoints") stop_all_streams() Schema evolution(Schema演化) Delta Lake 支持Schema演化,也就是说我们可以增加或改变表字段。接下去的批处理 SQL 会新增加一些数据,同时这些数据比之前的多了一个“closed”字段。我们将新的 DF 配置参数 mergeSchema 为 true 来显示指明 Delta Lake 表 Schema 的演化: cols = ['loan_id', 'funded_amnt', 'paid_amnt', 'addr_state', 'closed'] items = [ (1111111, 1000, 1000.0, 'TX', True), (2222222, 2000, 0.0, 'CA', False) ] loan_updates = spark.createDataFrame(items, cols) \ .withColumn("funded_amnt", col("funded_amnt").cast("int")) loan_updates.write.format("delta") \ .mode("append") \ .option("mergeSchema", "true") \ .save(delta_path) 来看一下插入新数据之后的表内容,新增加了 closed 字段,之前的老数据行这个字段默认为 null。 spark.read.format("delta").load(delta_path).show() +-------+-----------+---------+----------+------+ |loan_id|funded_amnt|paid_amnt|addr_state|closed| +-------+-----------+---------+----------+------+ | 0| 1000| 182.22| CA| null| | 1| 1000| 361.19| WA| null| | 2| 1000| 176.26| TX| null| | 3| 1000| 1000.0| OK| null| | 4| 1000| 249.98| PA| null| | 5| 1000| 408.6| CA| null| | 6| 1000| 1000.0| MD| null| | 7| 1000| 168.81| OH| null| | 8| 1000| 193.64| TX| null| | 9| 1000| 218.83| CT| null| | 10| 1000| 322.37| NJ| null| | 11| 1000| 400.61| NY| null| | 12| 1000| 1000.0| FL| null| | 13| 1000| 165.88| NJ| null| | 14| 1000| 190.6| TX| null| | 15| 1000| 1000.0| OH| null| | 16| 1000| 213.72| MI| null| | 17| 1000| 188.89| MI| null| | 18| 1000| 237.41| CA| null| | 19| 1000| 203.85| CA| null| +-------+-----------+---------+----------+------+ only showing top 20 rows 新的数据行具有 closed 字段: spark.read.format("delta").load(delta_path).filter(col("closed") == True).show() +-------+-----------+---------+----------+------+ |loan_id|funded_amnt|paid_amnt|addr_state|closed| +-------+-----------+---------+----------+------+ |1111111| 1000| 1000.0| TX| true| +-------+-----------+---------+----------+------+ Delta Lake 表的删除操作 除了常规的插入操作,Delta Lake 还支持 update 和 delete 等功能,可以更新表格内容。下面展示删除操作,我们希望删除表格中贷款已经被完全还清的记录。下面几条命令可以简单和清晰的展示删除过程。 首先,我们看看符合条件的记录有多少条: spark.sql("SELECT COUNT(*) FROM loans_delta WHERE funded_amnt = paid_amnt").show() +--------+ |count(1)| +--------+ | 5134| +--------+ 然后,我们执行一个 delete 命令: from delta.tables import * deltaTable = DeltaTable.forPath(spark, delta_path) deltaTable.delete("funded_amnt = paid_amnt") 最后,我们看一下删除后的结果,发现符合条件的记录都已被删除: spark.sql("SELECT COUNT(*) FROM loans_delta WHERE funded_amnt = paid_amnt").show() +--------+ |count(1)| +--------+ | 0| +--------+ 版本历史和回溯 Delta Lake 还具有很强大历史版本记录和回溯功能。history()方法清晰的展示了刚才那张表的修改记录,包括最后一次 Delete 操作。 deltaTable.history().show() +-------+-------------------+------+--------+----------------+--------------------+----+--------+---------+-----------+--------------+-------------+ |version| timestamp|userId|userName| operation| operationParameters| job|notebook|clusterId|readVersion|isolationLevel|isBlindAppend| +-------+-------------------+------+--------+----------------+--------------------+----+--------+---------+-----------+--------------+-------------+ | 10|2020-02-22 22:14:06| null| null| DELETE|[predicate -> ["(...|null| null| null| 9| null| false| | 9|2020-02-22 22:13:57| null| null| WRITE|[mode -> Append, ...|null| null| null| 8| null| true| | 8|2020-02-22 22:13:52| null| null|STREAMING UPDATE|[outputMode -> Ap...|null| null| null| 6| null| true| | 7|2020-02-22 22:13:50| null| null|STREAMING UPDATE|[outputMode -> Ap...|null| null| null| 6| null| true| | 6|2020-02-22 22:13:42| null| null|STREAMING UPDATE|[outputMode -> Ap...|null| null| null| 4| null| true| | 5|2020-02-22 22:13:40| null| null|STREAMING UPDATE|[outputMode -> Ap...|null| null| null| 4| null| true| | 4|2020-02-22 22:13:32| null| null|STREAMING UPDATE|[outputMode -> Ap...|null| null| null| 2| null| true| | 3|2020-02-22 22:13:30| null| null|STREAMING UPDATE|[outputMode -> Ap...|null| null| null| 2| null| true| | 2|2020-02-22 22:13:22| null| null|STREAMING UPDATE|[outputMode -> Ap...|null| null| null| 1| null| true| | 1|2020-02-22 22:13:20| null| null|STREAMING UPDATE|[outputMode -> Ap...|null| null| null| 0| null| true| | 0|2020-02-22 22:13:18| null| null| WRITE|[mode -> ErrorIfE...|null| null| null| null| null| true| +-------+-------------------+------+--------+----------------+--------------------+----+--------+---------+-----------+--------------+-------------+ 如果我们希望看一下刚才删除操作前的数据表状态,可以很方便的回溯到前一个快照点,并进行再次查询(我们可以看到被删除的记录又出现了)。 previousVersion = deltaTable.history(1).select("version").collect()[0][0] - 1 spark.read.format("delta") \ .option("versionAsOf", previousVersion) \ .load(delta_path) \ .createOrReplaceTempView("loans_delta_pre_delete") \ spark.sql("SELECT COUNT(*) FROM loans_delta_pre_delete WHERE funded_amnt = paid_amnt").show() +--------+ |count(1)| +--------+ | 5134| +--------+ 结论 本文通过 jupyter notebook 工具演示了 Delta Lake 的官方教程,你可以在本文末尾下载到完整的 notebook 文件。

优秀的个人博客,低调大师

16段代码入门Python循环语句

[ 导读 ]本文重点讲述for语句和while语句。for语句属于遍历循环,while语句属于当型循环。除了两个循环语句外,还介绍了break、continue与pass三个用于控制循环结构中的程序流向的语句。在此基础之上,也介绍了列表推导式,这是一种特殊的循环语句。 循环语句又称为重复结构,用于反复执行某一操作。面对大数量级的重复运算,即使借助计算机,重复编写代码也是费时的,这时就需要借助循环语句。使用循环语句一般要用到条件判断,根据判断式的返回值决定是否执行循环体。 循环分为两种模式,一种是条件满足时执行循环体,另一种则相反,在条件不满足时执行循环体。前者称为当型循环,后者称为直到型循环。 在图1中,虚线框内是一个当型循环结构,此结构包含判断条件和循环体,以及连接各部分的流向线。程序执行时,先判断条件的真假。判断为真时,则执行循环体;判断为假时,不再执行循环体,循环结束。当型循环先进行条件判断,如果满足循环条件,再执行循环体,因此又被称为前测试型循环。 在图2中,虚线框内是一个直到型循环结构,此结构包括判断条件和循环体,以及连接各部分的流向线。程序执行时,先执行一次循环体,再判断执行循环的结果是否满足判断条件。满足条件时,再次执行循环体;不满足条件时,不再执行循环体。直到型循环在执行判断前先进入循环体运行,因此又被称为后测试型循环。Python中主要有两种循环语句,即for语句和while语句。前者采用遍历的形式指定循环范围,后者视判断式返回值的情况而决定是否执行。要更灵活地操纵循环的流向,就要用到break、continue和pass等语句。 01 for for循环是迭代循环,在Python中相当于一个通用的序列迭代器,可以遍历任何有序序列,如str、list、tuple等,也可以遍历任何可迭代对象,如dict。不同于C语言,Python中的for语句将遍历系列中的所有成员,遍历顺序为成员在系列中的顺序。需要注意,在for循环中改变任何序列的内容都是危险的! for语句不属于当型循环或直到型循环,它遍历序列对象内的元素,对每个元素运行一次循环体,循环的步数在程序开始执行时已经指定,不属于条件判断。 在for语句中,for和in搭配组成for-in循环结构,for-in循环依次把list或tuple中的每个元素迭代出来。for语句的基本语法格式如下: for 变量 in 序列: 操作语句 for语句常用的语法格式及其参数说明如下所示: 序列:接收序列,表示遍历范围,无默认值 操作语句:接收操作语句,表示执行一段代码,无默认值 程序的执行从“for变量in序列”开始,该语句把序列中的每个元素代入变量,执行一遍操作语句1,重复的次数就是序列中元素的个数。为了展示for循环的遍历功能,依次打印list中的姓名,如代码清单1所示。 代码清单1:for语句遍历提取str ''' 遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,互帮互助, 群里还有不错的视频学习教程和PDF电子书! ''' # 单纯遍历的for语句 names = ['Michael', 'Bob', 'Tracy'] # 遍历输出names中的元素 for name in names: print(name) 输出结果: Michael Bob Tracy for语句同样可以实现dict的遍历方法,如代码清单2所示。 代码清单2:for语句遍历查询dict ''' 遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,互帮互助, 群里还有不错的视频学习教程和PDF电子书! ''' dic = {'a': 1, 'b': 2, 'c': 3, 'd': 4} # 遍历键值对 print('key_value:', end = '') for key, value in dic.items(): print(key, value, sep = ':', end = ' ') # 遍历键 print('keys:', end = '') for key in dic.keys(): print(key, end = ' ') # 遍历值 print('values:', end = '') for value in dic.values(): print(value, end = ' ') 输出结果: key_value:a:1 b:2 c:3 d:4 keys:a b c d values:1 2 3 4 从代码清单2可以看到,for语句中用于遍历的“变量”不仅可以是Python默认的指代词,也可以是常规的变量。 和条件语句一样,循环语句也可以使用嵌套,作用同样是丰富程序的功能性。设计一个成绩录入系统,就必然要录入姓名和课程这两类信息,仅靠一层循环是无法实现的,可使用两层循环结构,如代码清单3所示。 代码清单3:嵌套for语句 ''' 遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,互帮互助, 群里还有不错的视频学习教程和PDF电子书! ''' students = ['小明', '小红'] subjects = ['语文', '数学'] sum1 = [] avg = [] for i in students: print ('开始录入%s的考试成绩!'%i) sum = 0 for j in subjects: print('请输入%s成绩:'%j) score = int(input()) sum += score average = sum / 2 avg.append(average) sum1.append(sum) print(students, '的总分依次是', sum1, ',', '平均分依次是', avg) print('完成成绩录入!') 输出结果: 开始录入小明的考试成绩! 请输入语文成绩: 97 请输入数学成绩: 90 开始录入小红的考试成绩! 请输入语文成绩: 89 请输入数学成绩: 100 ['小明', '小红'] 的总分依次是 [187, 189] , 平均分依次是 [93.5, 94.5] 完成成绩录入! 理论上,for循环也可以无限嵌套,但并不推荐。 02 while while语句是Python中最常用的递归结构。区别于for循环,while循环结构包含条件判断式,是一种条件循环,属于当型循环。 while语句最基本的形式包括一个位于顶部的布尔表达式,一个或多个属于while代码块的缩进语句。也可以在结尾处包含一个else代码块,它与while代码块是同级的,组成while-else的形式。while语句的基本语法格式如下。 while 条件表达式: 操作语句 1 操作语句 2 while语句常用的参数及其说明如下所示: 条件表达式:接收布尔表达式,表示判断条件是否成立。无默认值 操作语句:接收操作语句,表示执行一段代码。无默认值 执行while语句时,只要顶部的条件表达式返回真值,就一直执行while部分嵌套的递归代码,当条件表达式返回假值时,不再执行操作语句,程序跳出while结构。 while语句的基础使用方法如代码清单4所示。 代码清单4:while语句 ''' 遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,互帮互助, 群里还有不错的视频学习教程和PDF电子书! ''' sum = 0 n = 99 while n > 0: sum += n n -= 2 print(sum) 输出结果:2500 如果布尔表达式不带有<、>、==、!=、in、not in等运算符,仅仅给出数值之类的条件,也是可以的。当while后写入一个非零整数时,视为真值,执行循环体;写入0时,视为假值,不执行循环体。也可以写入str、list或任何序列,长度非零则视为真值,执行循环体;否则视为假值,不执行循环体。 如果布尔表达式始终返回1,while语句就变成无限循环,如代码清单5所示。 代码清单5:while语句无限循环 ''' 遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,互帮互助, 群里还有不错的视频学习教程和PDF电子书! ''' # 布尔表达式为常数1,始终为真值 while 1: print('循环') 输出结果: 循环 循环 … # 布尔表达式每次递归运算都为2,始终为真值 x, y = 2, 1 while x / y: print('循环') x = x * 2 y = y * 2 输出结果: 循环 循环 … 运行代码清单5,将会不断打印出“循环”。代码清单5展示了制造无限循环的两种方式,既可以在while后写入一个固定的真值,也可以写入一个一直生成真值的表达式。要终止无限循环,可以使用快捷键Ctrl+C中断循环的执行,也可以用循环终止语句,这将在下文中介绍。 灵活地利用while语句中的布尔表达式及代入表达式的递归值,可以实现特别的功能,如代码清单6所示。 代码清单6:while语句实现str截取 ''' 遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,互帮互助, 群里还有不错的视频学习教程和PDF电子书! ''' string = 'abcd' while string: print(string) # 该语句的递归计算是,每次从str的第2个字符开始截取 string = string[1:] 输出结果: abcd bcd cd d 代码清单6包含一个自减迭代值,它并不通过明显的运算符实现自减,而是利用索引法则,x变量一直从str中第2个值截取至结尾,每次都将位于str最前面的字符截取掉,最终只剩下一个字符时,再次截取就只有空的结果,布尔表达式返回0,循环终止。 通过代码清单5和代码清单6可以看到,灵活地利用递归式,可以实现程序流向的控制。 while循环同样可以使用嵌套,嵌套的while循环实现成绩录入系统如代码清单7所示。 代码清单7:嵌套while语句 ''' 遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,互帮互助, 群里还有不错的视频学习教程和PDF电子书! ''' j = 1 while j <= 2: sum = 0 i = 1 name = input('请输入学生姓名:') while i <= 2: print ('请输入第%d门的考试成绩: '%i) sum += int(input()) i += 1 avg = sum / (i-1) print(name, '的平均成绩是%d'%avg) j += 1 print('学生成绩输入完成!') 输出结果: 请输入学生姓名:小明 请输入第1门的考试成绩: 98 请输入第2门的考试成绩: 88 小明 的平均成绩是93 请输入学生姓名:小红 请输入第1门的考试成绩: 65 请输入第2门的考试成绩: 100 小红 的平均成绩是82 学生成绩输入完成! 代码清单7的第1层while语句用于录入人名,第2层则在各人名下录入多门成绩,布尔表达式决定录入的人数和课程数。 03 break、continue与pass 在前两节中,已经介绍了Python中的两种循环语句。循环语句中还可以嵌入break、continue和pass语句,以灵活地改变流向,实现更多功能。 1. break 在Python中,break语句用于终止循环语句的执行。使用该语句时,即使循环条件判断为真,或序列未被完全递归,循环语句也会被立刻停止。 break语句一般配合条件判断使用,因为程序的终止必须是在某一条件被满足时执行。break语句在for循环和while循环中的使用如代码清单8所示。 代码清单8:break语句的使用 # break语句用于for循环 string = "Python" for i in string: # 遍历至string中的字符n时,不再执行else代码块 if i == 'n': break else: print("letter:{}". format(i)) 输出结果: letter:P letter:y letter:t letter:h letter:o ''' 遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,互帮互助, 群里还有不错的视频学习教程和PDF电子书! ''' # break语句用于while循环 counts = 0 while True: print(counts) counts += 1 # 满足counts等于3时跳出循环,不再进入循环体 if counts == 3: break 输出结果: 0 1 2 从代码清单8可以看到,break语句用于for循环和while循环是有区别的。用于for循环时,只终止遍历中某一次的循环体执行;用于while循环时,整个循环被终止。 break只终止本层循环,如有多层嵌套的循环,在其中一层循环中写入break,只在这层循环中生效,程序将跳到上一层循环中继续运行,如代码清单9所示。 代码清单9:break语句用于嵌套循环结构 ''' 遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,互帮互助, 群里还有不错的视频学习教程和PDF电子书! ''' # 第1层循环,遍历次数为2 for i in range(2): print("-----%d-----" %i) # 第2层循环,遍历次数为10 for j in range(10): # 使用break语句,j>1时不执行循环体 if j > 1: break print(j) 输出结果: -----0----- 0 1 -----1----- 0 1 在代码清单9中,break语句在条件判断式“if j>1:”后被使用,因此尽管j的指定遍历次数为10,实际上遍历只运行两次。由于break语句只终止本层循环的运行,i依旧遍历执行了两次,而不是在第1次遍历过程末尾终止。 2. continue Python中的continue语句用于跳出当前循环,并执行下一次循环,而break跳出整层循环,两者的功能具有明显区别。 如果一段代码中包含continue语句,循环执行至continue处时,先忽略本次循环,在本层仍满足条件的剩余循环次数中继续执行,不会终止这一层循环。实际上,如果在某一层的每次循环中都使用continue语句,就相当于使用break语句。 打印一个数表,要不打印某些指定的数字,或只打印某类数,就可以使用continue语句跳过一些循环次数,该语句在for循环和while循环中都可以自由地使用,如代码清单10所示。 代码清单10:continue语句用于循环结构 # 当i等于1或3时,跳过continue后的print语句 for i in range(0,5): if i == 1 or i == 3: continue print(i) 输出结果: 0 2 4 ''' 遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,互帮互助, 群里还有不错的视频学习教程和PDF电子书! ''' # 如果遇到偶数,跳过continue后的print语句 counts = 0 while counts < 10: counts += 1 if counts % 2 == 0: continue print(counts) 输出结果: 1 3 5 7 9 break语句一旦用于嵌套循环中的第n层,该层循环会被终止,但在执行第n-1层循环时,仍会创造一个第n层循环并执行。continue语句同样如此,只是仍会执行某一层的剩余部分。因此,无论使用哪种循环终止语句,都只会影响使用终止语句的那一层循环,而不会干扰到其他层。continue语句用于循环的例子如代码清单11所示。 代码清单11:continue语句用于嵌套循环结构 ''' 遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,互帮互助, 群里还有不错的视频学习教程和PDF电子书! ''' # 第1层循环,遍历次数为2 for i in range(2): print("-----%d-----" %i) # 第2层循环,遍历次数为5 for j in range(5): # 当j等于2或4时,不执行循环体 if j == 2 or j == 4: continue print(j) 输出结果: -----0----- 0 1 3 -----1----- 0 1 3 3. pass pass是空语句,不做任何操作,只起到占位的作用,其作用是为了保持程序结构的完整性。尽管pass语句不做任何操作,但如果暂时不确定要在一个位置放上什么样的代码,可以先放置一个pass语句,让代码可以正常运行。pass语句并非循环或者条件语句的一部分,但与break、continue在代码形式上有些类似。 使用pass语句遍历输出str及数值计算,如代码清单12所示。 代码清单12:pass语句 for element in "Python": # element为y时,不做任何操作,不会被输出 if element == "y": pass else: print(element) 输出结果: P t h o n ''' 遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,互帮互助, 群里还有不错的视频学习教程和PDF电子书! ''' counts = 0 while counts < 5: counts += 1 # i=3时,不执行循环体 if counts == 3: pass else: print(counts ** 2) 输出结果: 1 4 16 25 从代码清单12可以看到,Python在“P”和“t”之间占位,当循环遍历到“y”时不做任何操作;当i等于3时,幂运算不执行,但不影响其他数值。上述两个代码如果在pass的位置缺失,程序将无法执行,因为判断条件没有给出相应的执行语句,会导致逻辑出错。使用pass语句占位,一方面为了让程序正常执行,另一方面也是为了方便以后补充操作语句。 04 列表推导式 推导式是可以从一个数据序列构建另一个新的数据序列的结构体,能够非常简洁地构造新的变量。列表推导式是其中最常用的类型。 列表推导式又称为列表解析式,是Python迭代机制的一种应用,也是一种高效创建列list的方式,可以动态地创建list。由于列表推导式必须用到遍历循环,因此属于一种特殊的循环。 使用列表推导式时,需要将推导式写在[]中。list中的元素可以来源于其他类型序列、可迭代对象或自建的满足一定条件的序列。使用列表推导式的好处是代码更加简洁,实现效率更高。 列表推导式的基本语法格式如下: [操作语句 for变量 in 序列 if 条件表达式] 列表推导式常用的参数及其说明如下所示: 操作语句:接收操作语句,表示执行一段代码。无默认值 条件表达式:接收布尔表达式,表示判断条件是否成立。无默认值 序列:接收序列,表示遍历范围。无默认值 列表推导式可以不包含条件表达式,只做遍历,生成list,如代码清单13所示。 代码清单13:使用列表推导式生成list ''' 遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,互帮互助, 群里还有不错的视频学习教程和PDF电子书! ''' vec = [-4, -2, 0, 2, 4] # 用vec中元素的倍数,创建一个数组 print([x * 2 for x in vec]) 输出结果: [-8, -4, 0, 4, 8] # 创建一个包含2元tuple的list print([(x, x ** 2) for x in range(6)]) 输出结果: [(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)] 在代码清单13中,除了列表推导式的简单形式,还说明了列表推导式中可以使用多样的函数和变量类型。另外,列表推导式中也可以包含条件语句,如代码清单14所示。 代码清单14:包含条件语句的列表推导式 # 过滤list,删除list中的负数 print([x for x in vec if x >= 0]) 输出结果: [0, 2, 4] 列表推导式最大的优点还是简洁,这需要与常规的编程方式进行对比。如代码清单15所示,要创建一个平方数组成的list,这里的两种方式是等价的,但列表推导式的方式显然代码更加简洁。 代码清单15:常规方式与列表推导式对比 ''' 遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,互帮互助, 群里还有不错的视频学习教程和PDF电子书! ''' # 创建一个平方数list:常规方式 squares = [] for x in range(10): squares.append(x ** 2) print(squares) 输出结果: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] # 创建一个平方数list列表推导式 squares = [x ** 2 for x in range(10)] print(squares) 输出结果: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 列表推导式中同样可以实现嵌套循环,如代码清单16所示。 代码清单16:包含嵌套循环的列表推导式 # 打印由tuple组成的list,tuple中i由0至2,j由0至2 [(i, j) for i in range(0, 3) for j in range(0, 3)] 输出结果: [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)] # 打印由tuple组成的list,i在0至2之间且小于1,j在0至2之间且大于1 [(i, j) for i in range(0, 3) if i < 1 for j in range(0, 3) if j > 1] 输出结果: [(0, 2)] 代码清单16所示的列表推导式将两个不同list中的元素整合到了一起。列表推导式中包含一对括号,在括号中有一个表达式,表达式后面紧跟一条for语句,然后是零条或多条for语句或if语句。通过for语句和if语句计算出表达式,结果作为新list的元素。

优秀的个人博客,低调大师

基于Tensorflow的人工智能算法入门

coding=utf-8 引用数据分析模块 import numpy as np 引用文档读取模块,可以读取csv、json等文件 import pandas as pd 引用人工智能算法模块,里面包含相关算法 import tensorflow as tf 引用数据人工智能分析模块,并引用数据拆分功能 from sklearn.model_selection import train_test_split 初始化数据 从文件读取数据 data = pd.read_csv('data/XXX.csv') 为空值的列补充0值 data = data.fillna(0) 转换XX为1,XXX为2 data['XXX'] = data['XXX'].apply(lambda s: 1 if s == 'XXX' else 0) 添加新列Deceased 值为Survived 取非 独立热编码,就是使用N位布尔型的状态标识来对N种状态进行编码,任意时刻编码中只有一位有效(one-hot编码) data['XXX'] = data['XXX'].apply(lambda s: 1 - s) 选取特征字段用于分类 as_matrix : 在numpy中的特殊类型, 是作为array的子类出现,所以继承了array的所有特性并且有自己的特殊的地方, 专门用来处理线性代数操作(*表示矩阵的相乘,但是对于两个matrix的除/则表示对应元素的相除。) dataset_X = data[['XXX', 'XXX', 'XXX', 'XXX', 'XXX', 'XXX']].as_matrix()dataset_Y = data[['XXX', 'XXX']].as_matrix() 拆分数据为"训练数据集和验证数据集",其中验证数据集为20%(字段为test_size) train_test_split是交叉验证中常用的函数,功能是从样本中随机的按比例选取train data和testdata。 参数说明: train_data:所要划分的样本特征集 train_target:所要划分的样本结果 test_size:样本占比,如果是整数的话就是样本的数量 random_state:是随机数的种子。 随机数种子:其实就是该组随机数的编号,在需要重复试验的时候,保证得到一组一样的随机数。 比如你每次都填1,其他参数一样的情况下你得到的随机数组是一样的。但填0或不填,每次都会不一样。 随机数的产生取决于种子。 随机数和种子之间的关系遵从以下两个规则: 种子不同,产生不同的随机数;种子相同,即使实例不同也产生相同的随机数。 X_data, X_val, y_data,y_data_test_split(dataset_X, dataset_Y, test_size=0.2, random_state=42) 定义计算公式 声明输入数据占位符 shape 第一个参数为None,表示可以同时放入任意条记录 ================================================== tf.placeholder(dtype, shape=None, name=None) 此函数可以理解为形参,用于定义过程,在执行的时候再赋具体的值 参数: dtype:数据类型。常用的是tf.float32,tf.float64等数值类型 shape:数据形状。默认是None,就是一维值,也可以是多维,比如[2,3], [None, 3]表示列是3,行不定 name:名称 X = tf.placeholder(tf.float32, shape=[None, 6])y = tf.placeholder(tf.float32, shape=[None, 2]) 逻辑回归预测函数:y' = softmax(xW + b) 参数:x为输入向量,是大小为d x 1的列向量,d是特征数 tf.Variable是声明变量。 weights = tf.Variable(tf.random_normal([6, 2]), name='weights')bias = tf.Variable(tf.zeros([2]), name='bias') 下面为逻辑回归的预测函数的tf写法 tf.matmul 是矩阵乘法算子 tf.nn.softmax 是sofrmax 函数 y_pred = tf.nn.softmax(tf.matmul(X, weights) + bias) 下列是交叉熵的计算公式 Minimise cost using cross entropy NOTE: add a epsilon(1e-10) when calculate log(y_pred), otherwise the result will be -inf 使用交叉熵作为代价函数 1e-10 是误差值 当 y_pred 十分接近真值y_true 的时候,也就是y_pred 的值非常接近 0 或 1 时, 计算log(0)会得到负无穷 -inf,从而导致输出非法,全部都是 nan,并进一步导致 无法计算梯度,迭代陷入崩溃。 cross_entropy = - tf.reduce_sum(y * tf.log(y_pred + 1e-10), reduction_indices=1) 批量样本的代价值为所有样本交叉熵的平均值 cost = tf.reduce_mean(cross_entropy) 使用随机梯度下降算法优化器来最小化代价,系统自动构建反向传播部分的计算图 train_op = tf.train.GradientDescentOptimizer(0.001).minimize(cost) correct_pred = tf.equal(tf.argmax(y, 1), tf.argmax(y_pred, 1))acc_op = tf.reduce_mean(tf.cast(correct_pred, tf.float32)) 开始训练和分析模型 通过计算session来开启训练迭代 with tf.Session() as sess: # 初始化所有变量,必须最先执行 tf.global_variables_initializer().run() # 计算训练的循环,迭代10轮 for epoch in range(10): total_loss = 0. for i in range(len(X_train)): # 接口触发执行 feed_dict = {X: [X_train[i]], y: [y_train[i]]} _, loss = sess.run([train_op, cost], feed_dict=feed_dict) total_loss += loss # 评估校验数据集上的准确率 accuracy = sess.run(acc_op, feed_dict={X: X_val, y: y_val}) # 通过 NumPy 校验算法准确率 pred = sess.run(y_pred, feed_dict={X: X_val}) correct = np.equal(np.argmax(pred, 1), np.argmax(y_val, 1)) numpy_accuracy = np.mean(correct.astype(np.float32)) # 读取测试算法数据集 testdata = pd.read_csv('data/test.csv') testdata = testdata.fillna(0) # 转换XXX为1,XXX为2 testdata['XXX'] = testdata['XXX'].apply(lambda s: 1 if s == 'XXX' else 0) X_test = testdata[['XXX', 'XXX', 'XXX', 'XXX', 'XXX', 'XXX']] predictions = np.argmax(sess.run(y_pred, feed_dict={X: X_test}), 1) submission = pd.DataFrame({ "XXX": testdata["XXX"], "XXX": predictions })

优秀的个人博客,低调大师

【从入门到放弃-Java】并发编程-线程安全

概述 并发编程,即多条线程在同一时间段内“同时”运行。 在多处理器系统已经普及的今天,多线程能发挥出其优势,如:一个8核cpu的服务器,如果只使用单线程的话,将有7个处理器被闲置,只能发挥出服务器八分之一的能力(忽略其它资源占用情况)。同时,使用多线程,可以简化我们对复杂任务的处理逻辑,降低业务模型的复杂程度。 因此并发编程对于提高服务器的资源利用率、提高系统吞吐量、降低编码难度等方面起着至关重要的作用。 以上是并发编程的优点,但是它同样引入了一个很重要的问题:线程安全。 什么是线程安全问题 线程在并发执行时,因为cpu的调度等原因,线程会交替执行。如下图例子所示 public class SelfIncremental { private static int count; public static void main(S

优秀的个人博客,低调大师

Python3入门(十一)OS文件/目录方法

os模块提供了非常丰富的方法用来处理文件和目录。常用的方法如下表所示 方法 描述 os.access(path, mode) 检验权限模式 os.chdir(path) 改变当前工作目录 os.chflags(path, flags) 设置路径的标记为数字标记。 os.chmod(path, mode) 更改权限 os.chown(path, uid, gid) 更改文件所有者 os.chroot(path) 改变当前进程的根目录 os.close(fd) 关闭文件描述符 fd os.closerange(fd_low, fd_high) 关闭所有文件描述符,从 fd_low (包含) 到 fd_high (不包含), 错误会忽略 os.dup(fd) os.dup(fd) os.dup2(fd, fd2) 将一个文件描述符 fd 复制到另一个 fd2 os.fchdir(f

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册