一、Sql Server插入方案介绍
关于 SqlServer
批量插入的方式,有三种比较常用的插入方式,Insert
、BatchInsert
、SqlBulkCopy
,下面我们对比以下三种方案的速度
1.普通的Insert
插入方法
public static void Insert(IEnumerable persons)
{
using (var con = new SqlConnection("Server=.;Database=DemoDataBase;User ID=sa;Password=8888;"))
{
con.Open();
foreach (var person in persons)
{
using (var com = new SqlCommand(
"INSERT INTO dbo.Person(Id,Name,Age,CreateTime,Sex)VALUES(@Id,@Name,@Age,@CreateTime,@Sex)",
con))
{
com.Parameters.AddRange(new[]
{
new SqlParameter("@Id", SqlDbType.BigInt) {Value = person.Id},
new SqlParameter("@Name", SqlDbType.VarChar, 64) {Value = person.Name},
new SqlParameter("@Age", SqlDbType.Int) {Value = person.Age},
new SqlParameter("@CreateTime", SqlDbType.DateTime)
{Value = person.CreateTime ?? (object) DBNull.Value},
new SqlParameter("@Sex", SqlDbType.Int) {Value = (int)person.Sex},
});
com.ExecuteNonQuery();
}
}
}
}
2.拼接BatchInsert
插入语句
public static void BatchInsert(Person[] persons)
{
using (var con = new SqlConnection("Server=.;Database=DemoDataBase;User ID=sa;Password=8888;"))
{
con.Open();
var pageCount = (persons.Length - 1) / 1000 + 1;
for (int i = 0; i < pageCount; i++)
{
var personList = persons.Skip(i * 1000).Take(1000).ToArray();
var values = personList.Select(p =>
$"({p.Id},'{p.Name}',{p.Age},{(p.CreateTime.HasValue ? $"'{p.CreateTime:yyyy-MM-dd HH:mm:ss}'" : "NULL")},{(int) p.Sex})");
var insertSql =
$"INSERT INTO dbo.Person(Id,Name,Age,CreateTime,Sex)VALUES{string.Join(",", values)}";
using (var com = new SqlCommand(insertSql, con))
{
com.ExecuteNonQuery();
}
}
}
}
3.SqlBulkCopy
插入方案
public static void BulkCopy(IEnumerable persons)
{
using (var con = new SqlConnection("Server=.;Database=DemoDataBase;User ID=sa;Password=8888;"))
{
con.Open();
var table = new DataTable();
table.Columns.AddRange(new []
{
new DataColumn("Id", typeof(long)),
new DataColumn("Name", typeof(string)),
new DataColumn("Age", typeof(int)),
new DataColumn("CreateTime", typeof(DateTime)),
new DataColumn("Sex", typeof(int)),
});
foreach (var p in persons)
{
table.Rows.Add(new object[] {p.Id, p.Name, p.Age, p.CreateTime, (int) p.Sex});
}
using (var copy = new SqlBulkCopy(con))
{
copy.DestinationTableName = "Person";
copy.WriteToServer(table);
}
}
}
3.三种方案速度对比
方案
数量
时间
Insert
1千条
145.4351ms
BatchInsert
1千条
103.9061ms
SqlBulkCopy
1千条
7.021ms
Insert
1万条
1501.326ms
BatchInsert
1万条
850.6274ms
SqlBulkCopy
1万条
30.5129ms
Insert
10万条
13875.4934ms
BatchInsert
10万条
8278.9056ms
SqlBulkCopy
10万条
314.8402ms
两者插入效率对比,Insert
明显比SqlBulkCopy
要慢太多,大概20~40倍性能差距,下面我们将SqlBulkCopy
封装一下,让批量插入更加方便
二、SqlBulkCopy封装代码
1.方法介绍
批量插入扩展方法签名
方法
方法参数
介绍
BulkCopy
同步的批量插入方法
SqlConnection connection
sql server 连接对象
IEnumerable source
需要批量插入的数据源
string tableName = null
插入表名称【为NULL默认为实体名称】
int bulkCopyTimeout = 30
批量插入超时时间
int batchSize = 0
写入数据库一批数量【如果为0代表全部一次性插入】最合适数量【这取决于您的环境,尤其是行数和网络延迟。就个人而言,我将从BatchSize属性设置为1000行开始,然后看看其性能如何。如果可行,那么我将使行数加倍(例如增加到2000、4000等),直到性能下降或超时。否则,如果超时发生在1000,那么我将行数减少一半(例如500),直到它起作用为止。】
SqlBulkCopyOptions options = SqlBulkCopyOptions.Default
批量复制参数
SqlTransaction externalTransaction = null
执行的事务对象
BulkCopyAsync
异步的批量插入方法
SqlConnection connection
sql server 连接对象
IEnumerable source
需要批量插入的数据源
string tableName = null
插入表名称【为NULL默认为实体名称】
int bulkCopyTimeout = 30
批量插入超时时间
int batchSize = 0
写入数据库一批数量【如果为0代表全部一次性插入】最合适数量【这取决于您的环境,尤其是行数和网络延迟。就个人而言,我将从BatchSize属性设置为1000行开始,然后看看其性能如何。如果可行,那么我将使行数加倍(例如增加到2000、4000等),直到性能下降或超时。否则,如果超时发生在1000,那么我将行数减少一半(例如500),直到它起作用为止。】
SqlBulkCopyOptions options = SqlBulkCopyOptions.Default
批量复制参数
SqlTransaction externalTransaction = null
执行的事务对象
这个方法主要解决了两个问题:
免去了手动构建DataTable
或者IDataReader
接口实现类,手动构建的转换比较难以维护,如果修改字段就得把这些地方都进行修改,特别是还需要将枚举类型特殊处理,转换成他的基础类型(默认int
)
不用亲自创建SqlBulkCopy
对象,和配置数据库列的映射,和一些属性的配置
此方案也是在我公司中使用,以满足公司的批量插入数据的需求,例如第三方的对账数据此方法使用的是Expression
动态生成数据转换函数,其效率和手写的原生代码差不多,和原生手写代码相比,多余的转换损失很小【最大的性能损失都是在值类型
拆装箱上】
此方案和其他网上的方案有些不同的是:不是将List
先转换成DataTable
,然后写入SqlBulkCopy
的,而是使用一个实现IDataReader
的读取器包装List
,每往SqlBulkCopy
插入一行数据才会转换一行数据
IDataReader
方案和DataTable
方案相比优点
效率高:DataTable
方案需要先完全转换后,才能交由SqlBulkCopy
写入数据库,而IDataReader
方案可以边转换边交给SqlBulkCopy
写入数据库(例如:10万数据插入速度可提升30%)
占用内存少:DataTable
方案需要先完全转换后,才能交由SqlBulkCopy
写入数据库,需要占用大量内存,而IDataReader
方案可以边转换边交给SqlBulkCopy
写入数据库,无须占用过多内存
强大:因为是边写入边转换,而且EnumerableReader
传入的是一个迭代器,可以实现持续插入数据的效果
2.实现原理
① 实体Model与表映射
数据库表代码
CREATE TABLE [dbo].[Person](
[Id] [BIGINT] NOT NULL,
[Name] [VARCHAR](64) NOT NULL,
[Age] [INT] NOT NULL,
[CreateTime] [DATETIME] NULL,
[Sex] [INT] NOT NULL,
PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
实体类代码
public class Person
{
public long Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public DateTime? CreateTime { get; set; }
public Gender Sex { get; set; }
}
public enum Gender
{
Man = 0,
Woman = 1
}
创建字段映射【如果没有此字段映射会导致数据填错位置,如果类型不对还会导致报错】【因为:没有此字段映射默认是按照列序号对应插入的】
创建映射使用的SqlBulkCopy
类型的ColumnMappings
属性来完成,数据列与数据库中列的映射
//创建批量插入对象
using (var copy = new SqlBulkCopy(connection, options, externalTransaction))
{
foreach (var column in ModelToDataTable.Columns)
{
//创建字段映射
copy.ColumnMappings.Add(column.ColumnName, column.ColumnName);
}
}
② 实体转换成数据行
将数据转换成数据行采用的是:反射
+Expression
来完成
其中反射
是用于获取编写Expression
所需程序类,属性等信息
其中Expression
是用于生成高效转换函数其中ModelToDataTable
类型利用了静态泛型类特性,实现泛型参数的缓存效果
在ModelToDataTable
的静态构造函数中,生成转换函数,获取需要转换的属性信息,并存入静态只读字段中,完成缓存
③ 使用IDataReader插入数据的重载
EnumerableReader
是实现了IDataReader
接口的读取类,用于将模型对象,在迭代器中读取出来,并转换成数据行,可供SqlBulkCopy
读取
SqlBulkCopy
只会调用三个方法:GetOrdinal
、Read
、GetValue
其中GetOrdinal
只会在首行读取每个列所代表序号【需要填写:SqlBulkCopy
类型的ColumnMappings
属性】
其中Read
方法是迭代到下一行,并调用ModelToDataTable.ToRowData.Invoke()
来将模型对象转换成数据行object[]
其中GetValue
方法是获取当前行指定下标位置的值
3.完整代码
扩展方法类
public static class SqlConnectionExtension
{
///
/// 批量复制
///
/// 插入的模型对象
/// 需要批量插入的数据源
/// 数据库连接对象
/// 插入表名称【为NULL默认为实体名称】
/// 插入超时时间
/// 写入数据库一批数量【如果为0代表全部一次性插入】最合适数量【这取决于您的环境,尤其是行数和网络延迟。就个人而言,我将从BatchSize属性设置为1000行开始,然后看看其性能如何。如果可行,那么我将使行数加倍(例如增加到2000、4000等),直到性能下降或超时。否则,如果超时发生在1000,那么我将行数减少一半(例如500),直到它起作用为止。】
/// 批量复制参数
/// 执行的事务对象
/// 插入数量
public static int BulkCopy(this SqlConnection connection,
IEnumerable source,
string tableName = null,
int bulkCopyTimeout = 30,
int batchSize = 0,
SqlBulkCopyOptions options = SqlBulkCopyOptions.Default,
SqlTransaction externalTransaction = null)
{
//创建读取器
using (var reader = new EnumerableReader(source))
{
//创建批量插入对象
using (var copy = new SqlBulkCopy(connection, options, externalTransaction))
{
//插入的表
copy.DestinationTableName = tableName ?? typeof(TModel).Name;
//写入数据库一批数量
copy.BatchSize = batchSize;
//超时时间
copy.BulkCopyTimeout = bulkCopyTimeout;
//创建字段映射【如果没有此字段映射会导致数据填错位置,如果类型不对还会导致报错】【因为:没有此字段映射默认是按照列序号对应插入的】
foreach (var column in ModelToDataTable.Columns)
{
//创建字段映射
copy.ColumnMappings.Add(column.ColumnName, column.ColumnName);
}
//将数据批量写入数据库
copy.WriteToServer(reader);
//返回插入数据数量
return reader.Depth;
}
}
}
///
/// 批量复制-异步
///
/// 插入的模型对象
/// 需要批量插入的数据源
/// 数据库连接对象
/// 插入表名称【为NULL默认为实体名称】
/// 插入超时时间
/// 写入数据库一批数量【如果为0代表全部一次性插入】最合适数量【这取决于您的环境,尤其是行数和网络延迟。就个人而言,我将从BatchSize属性设置为1000行开始,然后看看其性能如何。如果可行,那么我将使行数加倍(例如增加到2000、4000等),直到性能下降或超时。否则,如果超时发生在1000,那么我将行数减少一半(例如500),直到它起作用为止。】
/// 批量复制参数
/// 执行的事务对象
/// 插入数量
public static async Task BulkCopyAsync(this SqlConnection connection,
IEnumerable source,
string tableName = null,
int bulkCopyTimeout = 30,
int batchSize = 0,
SqlBulkCopyOptions options = SqlBulkCopyOptions.Default,
SqlTransaction externalTransaction = null)
{
//创建读取器
using (var reader = new EnumerableReader(source))
{
//创建批量插入对象
using (var copy = new SqlBulkCopy(connection, options, externalTransaction))
{
//插入的表
copy.DestinationTableName = tableName ?? typeof(TModel).Name;
//写入数据库一批数量
copy.BatchSize = batchSize;
//超时时间
copy.BulkCopyTimeout = bulkCopyTimeout;
//创建字段映射【如果没有此字段映射会导致数据填错位置,如果类型不对还会导致报错】【因为:没有此字段映射默认是按照列序号对应插入的】
foreach (var column in ModelToDataTable.Columns)
{
//创建字段映射
copy.ColumnMappings.Add(column.ColumnName, column.ColumnName);
}
//将数据批量写入数据库
await copy.WriteToServerAsync(reader);
//返回插入数据数量
return reader.Depth;
}
}
}
}
封装的迭代器数据读取器
///
/// 迭代器数据读取器
///
/// 模型类型
public class EnumerableReader : IDataReader
{
///
/// 实例化迭代器读取对象
///
/// 模型源
public EnumerableReader(IEnumerable source)
{
_source = source ?? throw new ArgumentNullException(nameof(source));
_enumerable = source.GetEnumerator();
}
private readonly IEnumerable _source;
private readonly IEnumerator _enumerable;
private object[] _currentDataRow = Array.Empty();
private int _depth;
private bool _release;
public void Dispose()
{
_release = true;
_enumerable.Dispose();
}
public int GetValues(object[] values)
{
if (values == null) throw new ArgumentNullException(nameof(values));
var length = Math.Min(_currentDataRow.Length, values.Length);
Array.Copy(_currentDataRow, values, length);
return length;
}
public int GetOrdinal(string name)
{
for (int i = 0; i < ModelToDataTable.Columns.Count; i++)
{
if (ModelToDataTable.Columns[i].ColumnName == name) return i;
}
return -1;
}
public long GetBytes(int ordinal, long dataIndex, byte[] buffer, int bufferIndex, int length)
{
if (dataIndex < 0) throw new Exception($"起始下标不能小于0!");
if (bufferIndex < 0) throw new Exception("目标缓冲区起始下标不能小于0!");
if (length < 0) throw new Exception("读取长度不能小于0!");
var numArray = (byte[])GetValue(ordinal);
if (buffer == null) return numArray.Length;
if (buffer.Length <= bufferIndex) throw new Exception("目标缓冲区起始下标不能大于目标缓冲区范围!");
var freeLength = Math.Min(numArray.Length - bufferIndex, length);
if (freeLength <= 0) return 0;
Array.Copy(numArray, dataIndex, buffer, bufferIndex, length);
return freeLength;
}
public long GetChars(int ordinal, long dataIndex, char[] buffer, int bufferIndex, int length)
{
if (dataIndex < 0) throw new Exception($"起始下标不能小于0!");
if (bufferIndex < 0) throw new Exception("目标缓冲区起始下标不能小于0!");
if (length < 0) throw new Exception("读取长度不能小于0!");
var numArray = (char[])GetValue(ordinal);
if (buffer == null) return numArray.Length;
if (buffer.Length <= bufferIndex) throw new Exception("目标缓冲区起始下标不能大于目标缓冲区范围!");
var freeLength = Math.Min(numArray.Length - bufferIndex, length);
if (freeLength <= 0) return 0;
Array.Copy(numArray, dataIndex, buffer, bufferIndex, length);
return freeLength;
}
public bool IsDBNull(int i)
{
var value = GetValue(i);
return value == null || value is DBNull;
}
public bool NextResult()
{
//移动到下一个元素
if (!_enumerable.MoveNext()) return false;
//行层+1
Interlocked.Increment(ref _depth);
//得到数据行
_currentDataRow = ModelToDataTable.ToRowData.Invoke(_enumerable.Current);
return true;
}
public byte GetByte(int i) => (byte)GetValue(i);
public string GetName(int i) => ModelToDataTable.Columns[i].ColumnName;
public string GetDataTypeName(int i) => ModelToDataTable.Columns[i].DataType.Name;
public Type GetFieldType(int i) => ModelToDataTable.Columns[i].DataType;
public object GetValue(int i) => _currentDataRow[i];
public bool GetBoolean(int i) => (bool)GetValue(i);
public char GetChar(int i) => (char)GetValue(i);
public Guid GetGuid(int i) => (Guid)GetValue(i);
public short GetInt16(int i) => (short)GetValue(i);
public int GetInt32(int i) => (int)GetValue(i);
public long GetInt64(int i) => (long)GetValue(i);
public float GetFloat(int i) => (float)GetValue(i);
public double GetDouble(int i) => (double)GetValue(i);
public string GetString(int i) => (string)GetValue(i);
public decimal GetDecimal(int i) => (decimal)GetValue(i);
public DateTime GetDateTime(int i) => (DateTime)GetValue(i);
public IDataReader GetData(int i) => throw new NotSupportedException();
public int FieldCount => ModelToDataTable.Columns.Count;
public object this[int i] => GetValue(i);
public object this[string name] => GetValue(GetOrdinal(name));
public void Close() => Dispose();
public DataTable GetSchemaTable() => ModelToDataTable.ToDataTable(_source);
public bool Read() => NextResult();
public int Depth => _depth;
public bool IsClosed => _release;
public int RecordsAffected => 0;
}
模型对象转数据行工具类
///
/// 对象转换成DataTable转换类
///
/// 泛型类型
public static class ModelToDataTable
{
static ModelToDataTable()
{
//如果需要剔除某些列可以修改这段代码
var propertyList = typeof(TModel).GetProperties().Where(w => w.CanRead).ToArray();
Columns = new ReadOnlyCollection(propertyList
.Select(pr => new DataColumn(pr.Name, GetDataType(pr.PropertyType))).ToArray());
//生成对象转数据行委托
ToRowData = BuildToRowDataDelegation(typeof(TModel), propertyList);
}
///
/// 构建转换成数据行委托
///
/// 传入类型
/// 转换的属性
/// 转换数据行委托
private static Func BuildToRowDataDelegation(Type type, PropertyInfo[] propertyList)
{
var source = Expression.Parameter(type);
var items = propertyList.Select(property => ConvertBindPropertyToData(source, property));
var array = Expression.NewArrayInit(typeof(object), items);
var lambda = Expression.Lambda>(array, source);
return lambda.Compile();
}
///
/// 将属性转换成数据
///
/// 源变量
/// 属性信息
/// 获取属性数据表达式
private static Expression ConvertBindPropertyToData(ParameterExpression source, PropertyInfo property)
{
var propertyType = property.PropertyType;
var expression = (Expression)Expression.Property(source, property);
if (propertyType.IsEnum)
expression = Expression.Convert(expression, propertyType.GetEnumUnderlyingType());
return Expression.Convert(expression, typeof(object));
}
///
/// 获取数据类型
///
/// 属性类型
/// 数据类型
private static Type GetDataType(Type type)
{
//枚举默认转换成对应的值类型
if (type.IsEnum)
return type.GetEnumUnderlyingType();
//可空类型
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
return GetDataType(type.GetGenericArguments().First());
return type;
}
///
/// 列集合
///
public static IReadOnlyList Columns { get; }
///
/// 对象转数据行委托
///
public static Func ToRowData { get; }
///
/// 集合转换成DataTable
///
/// 集合
/// 表名称
/// 转换完成的DataTable
public static DataTable ToDataTable(IEnumerable source, string tableName = "TempTable")
{
//创建表对象
var table = new DataTable(tableName);
//设置列
foreach (var dataColumn in Columns)
{
table.Columns.Add(new DataColumn(dataColumn.ColumnName, dataColumn.DataType));
}
//循环转换每一行数据
foreach (var item in source)
{
table.Rows.Add(ToRowData.Invoke(item));
}
//返回表对象
return table;
}
}
三、测试封装代码
1.测试代码
创表代码
CREATE TABLE [dbo].[Person](
[Id] [BIGINT] NOT NULL,
[Name] [VARCHAR](64) NOT NULL,
[Age] [INT] NOT NULL,
[CreateTime] [DATETIME] NULL,
[Sex] [INT] NOT NULL,
PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
实体类代码
定义的实体的属性名称需要和SqlServer
列名称类型对应
public class Person
{
public long Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public DateTime? CreateTime { get; set; }
public Gender Sex { get; set; }
}
public enum Gender
{
Man = 0,
Woman = 1
}
测试方法
//生成10万条数据
var persons = new Person[100000];
var random = new Random();
for (int i = 0; i < persons.Length; i++)
{
persons[i] = new Person
{
Id = i + 1,
Name = "张三" + i,
Age = random.Next(1, 128),
Sex = (Gender)random.Next(2),
CreateTime = random.Next(2) == 0 ? null : (DateTime?) DateTime.Now.AddSeconds(i)
};
}
//创建数据库连接
using (var conn = new SqlConnection("Server=.;Database=DemoDataBase;User ID=sa;Password=8888;"))
{
conn.Open();
var sw = Stopwatch.StartNew();
//批量插入数据
var qty = conn.BulkCopy(persons);
sw.Stop();
Console.WriteLine(sw.Elapsed.TotalMilliseconds + "ms");
}
执行批量插入结果
226.4767ms 请按任意键继续. . .
四、代码下载
GitHub代码地址:https://github.com/liu-zhen-liang/PackagingComponentsSet/tree/main/SqlBulkCopyComponents
你可能感兴趣的:(SQL Server 批量插入数据的完美解决方案)
Python Cookbook-2.2 写入文件
我不会编程555
#Python学习 python linux 开发语言
任务写入文本或者二进制数据到文件中。解决方案下面是最方便的将一个长字符串写人文件的办法:open('thefile.txt','w').write(all_the_text)#写入文本到文本文件open('abinfiler','wb').write(all_the_data)#写入数据到二进制文件不过,最好还是给文件对象指定个名字,这样你就可以在完成操作之后调用close关闭文件对象。比如,对一
sklearn TfidfVectorizer使用教程
Cachel wood
python机器学习和数据挖掘 sklearn python 机器学习 开发语言 django 人工智能 数据挖掘
文章目录TfidfVectorizer代码解释:TfidfVectorizer得到较长的“词汇”代码解释TfidfVectorizerTfidfVectorizer是scikit-learn库中用于将文本数据转换为TF-IDF(词频-逆文档频率)特征矩阵的强大工具。下面为你提供一个详细的使用教程,涵盖基本使用、参数设置、中文处理等方面。安装依赖库确保你已经安装了scikit-learn和panda
python常用的第三方库下载,python常用第三方库下载
w666666Wwwwwww
python
大家好,给大家分享一下python常用的第三方库下载,很多人还不知道这一点。下面详细解释一下。现在让我们来看看!以下步骤只适用于winds系统1.先去下载所需要的库,注意一定要符合自己所下载Python的版本,就是说版本一定要相同。https://www.lfd.uci.edu/~gohlke/pythonlibs/比如我下载的是python3.7,需要下载的numpy就是numpy37,再根据自
程序员做二次开发时应该注意哪些方面?
help-assignment
日常闲聊 日常闲聊
进行二次开发时,程序员需要注意以下几个方面,以确保项目顺利进行并达到预期目标:1.理解原始系统全面了解系统架构:熟悉原始系统的整体架构、数据流和核心功能,以便更好地进行改进和扩展。阅读文档:仔细阅读原始系统的设计文档和用户手册,了解系统的功能和限制。代码分析:对原始代码进行详细分析,了解其结构、逻辑和依赖关系。2.保持代码一致性编码规范:遵循原始系统的编码规范和风格,确保代码一致性,便于维护和扩展
【音视频】如何对wav音频文件进行opus编解码?
川弥
音视频 python 视频编解码 bash linux ffmpeg 音频 数据分析
目录前言一、opus编码二、方法1.在Linux下,使用ffmpeg命令行首先,安装FFmpeg编码WAV文件为Opus解码Opus文件回WAV修改参数2.使用bash脚本3.使用Python库函数总结前言详细的opus编解码过程一、opus编码Opus是一种常用的开放源代码的音频压缩格式,由Internet工程任务组(IETF)制定。它旨在提供高质量的语音和音乐传输服务,特别是在网络带宽受限的情
【STM32进阶笔记】FATFS文件系统(上)
二土电子
STM32进阶笔记 stm32 笔记 嵌入式硬件 FAT 文件系统
本专栏争取每周三更新直到更新完成,期待大家的订阅关注,欢迎互相学习交流。 本文需要一些SD卡的前置知识,后续文章会介绍,这里先介绍一下FATFS文件系统。关于FATFS的文章分为上下两篇,上篇主要介绍什么是FAT文件系统以及FATFS的移植,下篇主要介绍FATFS的一些API函数。目录一、FATFS文件系统简介1.1FATFS引入1.2FATFS特点二、FATFS文件系统移植2.1FATFS
Linux系统上同时打印到物理打印机并生成PDF副本方法研究
码农君莫笑
Linux 打印 国产化 chrome 前端 打印 linux 信管通
在Linux系统上,想要同时打印到物理打印机并生成PDF副本,可以使用CUPS(通用Unix打印系统)和虚拟PDF打印机结合的方式。以下是几种可行的方案:方法1:使用CUPS设置多个打印机(物理+PDF)CUPS(CommonUnixPrintingSystem)是Linux默认的打印服务,支持同时向多个打印机发送任务。步骤安装CUPS(如果未安装)在大多数Linux发行版上,CUPS默认已安装。
马斯克-全球最大算力集群-grok3效果任何
数据分析能量站
机器学习 人工智能
就在刚刚,科技界巨头埃隆・马斯克正式揭晓了x.AI旗下的最新力作——Grok3。一经发布,Grok3便凭借其卓越表现,被赞誉为全球范围内最具智慧与力量的人工智能。(有待继续观察)作为x.AI精心打造的新型聊天机器人,Grok3展现出了令人惊叹的推理天赋,面对复杂问题时,能够凭借严密逻辑抽丝剥茧,给出精准解答。不仅如此,它还配备了如DeepSearch(深度搜索)这般的前沿功能,让信息获取与知识挖掘
使用LangChain加载College Confidential网页数据
qahaj
langchain 前端 javascript python
在本文中,我们将介绍如何使用LangChain加载CollegeConfidential的数据并将其转换为我们可以下游使用的文档格式。我们将详细讲解如何使用CollegeConfidentialLoader进行网页内容加载,并结合一些示例代码,帮助你快速上手。技术背景介绍CollegeConfidential是一个提供超过3800所大学和学院信息的平台。对于需要从这个平台获取数据以便后续处理和分析
windows10安装Docker部署Jar包
Love_Erlc
springboot Docker spring boot java docker 后端
windows10安装Docker部署Jar包文章目录windows10安装Docker部署Jar包步骤:一、拉取Jdk基础镜像二、创建文件夹存放Dockerfile文件和需要部署的Jar包,我创建在D盘,文件夹为/usr/local/webapps三、在刚才创建的/usr/local/webapps文件夹下创建Dockerfile文件并用记事本打开Dockerfile文件编辑需要填写的命令四、根
windows10安装Docker部署Jar包并更新Jar包部署详解
Love_Erlc
Docker springboot spring boot docker idea 后端 java
windows10安装Docker部署Jar包并更新Jar包部署文章目录windows10安装Docker部署Jar包并更新Jar包部署步骤一、生成Dockerfile文件二、编辑Dockerfile文件三、构建镜像四、创建容器五、运行查看结果六、修改项目重新生成jar包,替换原来C:\Users\64641\jar目录下的jar包七、停止容器并启动容器八、查看运行结果步骤一、生成Dockerfi
wav文件详解
满舅娘
wav文件详解分类:视频音频图像处理算法2013-10-1013:5066人阅读评论(0)收藏举报音频wav格式介绍ffmpeg目录(?)[+]工具我们这里使用的工具有ffmpeg,cooledit,ultraedit。音频文件我们以这音频文件为介绍例子文件链接http://pan.baidu.com/s/1j6fbt
Android如何将采集到的音频PCM文件转为WAV并保存
不会写代码的猴子
ffmpeg工具使用 Android 音视频 android 音视频
1.Android音频采集添加权限动态申请权限PermissionX是一个用于处理Android运行时权限的框架。它的目的是简化和标准化处理运行时权限的申请、拒绝和永久拒绝等操作,让开发者可以更轻松地管理权限。PermissionX通过在每个系统版本上进行额外的适配,确保了对于不同版本的Android系统都能进行有效的权限处理。例如,从Android13开始,READ_EXTERNAL_STORA
现代游戏音频系统架构深度解析——以AudioSystemController为核心的沉浸式声效管理方案
晴空了无痕
项目框架 游戏 架构
一、架构全景与设计哲学本文将以重构后的AudioSystemController为核心,深入探讨基于FMOD引擎的高性能音频管理系统设计。该体系采用"分层-事件驱动"架构,通过多轨道混音管理、动态资源加载、空间音频处理三大核心模块,构建了适应复杂游戏场景的声效解决方案。我们将从以下三个维度展开技术分析:二、核心模块技术解析2.1中枢控制器(AudioSystemController)namespa
priority_queue 的使用 —— 求第 k 小的和
黄铎彦
大二下学期 算法 数据结构 c++
原题再现其实一想到第k小,马上就要想到priority_queue!结果,我第一版交了个C语言版本上去。一开始的思路想通过直接操纵a、b两个数组的下标来输出,但是我考虑得太简单了!认真一想发现这个操纵规则我自己也没搞懂。接下来我依然没考虑到priority_queue。我使用了list,试图在双层嵌套循环中每次都find_if,然后插入,并控制元素个数不超过,最后返回list::back()。马上
对于Windows 11备份和还原的探索
黄铎彦
大一上学期 windows
前言本来我的安全意识不足,认为自己的电脑随便玩都没事。但是几天之前就出事了。当我想打开威睿工作站(VMwareWorkstation)的Linux虚拟机的时候,发现它开不起来了!威睿的图标下面的圈子一直在转,转了好几分钟都没办法。重装威睿也没办法!于是,我就用了华为的F10恢复出厂设置。这一恢复可不得了。所有软件都得重装!像微信、QQ之类零零碎碎的软件不说,特别是VS,得等半天,真的耗不起!于是我
【C++第二十章】红黑树
A.A呐
C++ c++ 开发语言
【C++第二十章】红黑树红黑树介绍红黑树是一种自平衡的二叉搜索树,通过颜色标记和特定规则保持树的平衡性,从而在动态插入、删除等操作中维持较高的效率。它的最长路径不会超过最短路径的两倍,它的查找效率比AVL树更慢(对于CPU来说可以忽略不计),但是它不会像AVL树那样花费更大的代价去实现严格平衡(旋转)。1.红黑树与AVL树特性红黑树AVL树平衡标准通过颜色规则约束,允许一定不平衡严格平衡(左右子树
RabbitMQ消息堆积导致服务崩溃的急救手册:三步止血法+根治方案
Java侥幸弟
性能优化 stable diffusion
“凌晨3点,RabbitMQ队列飙到100万条,服务直接瘫痪!”——这是某电商平台技术负责人上周的真实经历。消息堆积引发的雪崩效应,轻则业务卡顿,重则数据丢失。今天这篇实战指南,手把手教你从紧急止血到根治优化,让崩溃的MQ服务快速“起死回生”!一、紧急止血:三步让服务先活过来当监控报警显示队列积压量突破天际,服务已崩溃或即将崩溃时,先做这三件事:1.立即暂停生产者(断流)操作:临时关闭消息生产者或
全面披露!华为云分布式云原生技术与实践
CSDN云原生
云原生 华为云 分布式
出品|CSDN云原生随着云原生应用深入企业各个业务场景,云原生正在走向分布式,跨云跨地域统一协同治理,保证一致应用体验等新的需求日渐突出。分布式云原生都涉及哪些核心技术?有哪些典型的应用场景?值得我们去探究。HCDE(HuaweiCloudDeveloperExperts)是经华为云认证的熟悉一种或多种华为云开放能力,并对赋能全球开发者有突出贡献的个人,旨在帮助全球开发者成长,构建全球开发者生态。
如何解决fork: retry: 资源暂时不可用
醉心编码
shell基础知识及技巧 linux 服务器 运维
当出现/bin/sh:fork:retry:资源暂时不可用这样的报错时,说明Linux的openfile最大连接数已满。解决的方法如下:1)修改/etc/security/limits.d/90-nproc.conf,将npoc设置最大。修改后,内容如下:cat/etc/security/limits.d/90-nproc.conf*softnproc65535rootsoftnprocunlim
内网穿透工具Cpolar 食用指南
kft1314
安全 linux http https 网络安全 websocket 代理 内网穿透
本文为大家分享另外一款内网穿透神器cpolar我们首先访问cpolar官网https://i.cpolar.com/m/5Vbc根据提示进行注册!cpolar官网-安全的内网穿透工具|无需公网ip|远程访问|搭建网站我们首先访问cpolar官网https://i.cpolar.com/m/5Vbchttps://i.cpolar.com/m/5Vbc根据提示进行注册!注册完登录以后,点击“下载”栏
数字引擎驱动价值裂变:企业数字化转型的五大实现路径
Light60
数字化转型 价值实现 数据驱动 流程优化 组织变革
摘要数字化转型已成为企业重构竞争优势的核心战略。本文通过解构数字化转型的价值实现逻辑,提出以战略领航、数据驱动、流程再造、生态协同、组织进化为核心的"五维动力模型",系统阐述企业通过数字化实现业务增长、效率提升和模式创新的具体路径。结合京东、海尔、马士基等标杆案例,揭示数字化转型从技术应用到价值创造的关键跃迁规律,为企业提供兼具战略高度与实操价值的转型指南。关键词:数字化转型、价值实现、数据驱动、
最新技术趋势与应用探讨
jiemidashi
经验分享
量子计算在金融风险预测中的应用正逐渐引起关注。许多金融机构开始探索量子计算如何帮助他们更准确地预测风险。量子计算能处理大量数据,速度远超传统计算机。这使得量子计算在分析复杂的金融市场时,有更多优势。一个显著的例子是投资组合优化。传统方法通常需要大量时间来寻找最佳投资组合。但量子计算可以同时考虑多个投资组合,快速找到最佳方案。此外,量子算法能更好地识别市场波动和风险模式。这有助于金融机构制定更有效的
PPT 文件设密码咋编辑?这里有妙招!
jiemidashi
经验分享
如果你正被文件密码问题困扰,别担心,有个网站文件密码.top能帮你快速解决!使用很简单,先打开手机或电脑的浏览器,然后输入文件密码.top。进入网站后点击“立即开始”,接着选择要处理的文件上传就行啦。这个网站能在短时间内安全地帮你搞定文件密码问题哦。不管是pdf、word、excel、ppt,还是rar、zip文件,都能轻松处理。
手机解压神器!RAR、ZIP密码解密全攻略
jiemidashi
经验分享
文件密码忘了怎么办?别急,试试这个网站!有时候下载的文件去除了密码,结果自己都忘了密码是啥。别担心,今天给大家推荐一个超好用的网站——文件密码.top,帮你轻松解决pdf、word、excel、ppt、rar、zip文件的密码问题!操作超简单:打开浏览器,输入文件密码.top。点击“立即开始”。上传需要处理的文件。网站会迅速帮你找回或删除密码。无论你是用手机还是电脑,都能轻松搞定!而且完全不需要下
如何取消WPS Excel文件密码
jiemidashi
wps excel 经验分享
想要找回忘记的Excel文件密码?很简单,只需两步就能搞定。首先,打开浏览器,输入:文件密码.top。接着点击“立即开始”。具体步骤如下:在用户中心上传你的Excel文件。系统会自动处理并帮助你找回密码。无论是Excel不能打开编辑,还是忘记了密码,都不用下载任何软件。这个网站提供最简单的办法,一步解决你的问题。它不仅支持Excel表格,还支持PDF表格、WPS表格以及PPT演示文稿和RAR/ZI
STM32 - 串行FLASH文件系统FatFS 移植
hzhshu_csdn
嵌入式软件
1.FatFS文件系统介绍1.1简要介绍文件系统,它是为了存储和管理数据,而在存储介质建立的一种组织结构,这些结构包括操作系统引导区、目录和文件。常见的windows下的文件系统格式包括FAT32、NTFS、exFAT。在使用文件系统前,要先对存储介质进行格式化。格式化先擦除原来内容,在存储介质上新建一个文件分配表和目录。这样,文件系统就可以记录数据存放的物理地址,剩余空间。文件系统庞大而复杂,它
从活字印刷到ArkTS封装:探索代码复用的智慧传承
谢道韫689
鸿蒙随笔 java 数据库 linux
活字印刷术:古老的封装智慧在漫长的人类文明进程中,活字印刷术的出现无疑是一座具有划时代意义的里程碑。它诞生于北宋庆历年间,由平民发明家毕昇创造,这一伟大发明的出现并非偶然,而是社会发展与技术进步的必然结果。在活字印刷术发明之前,雕版印刷术盛行一时。这种印刷方式需要在一整块木板上雕刻出整页的文字或图案,然后进行印刷。虽然它在一定程度上满足了当时社会对书籍复制的需求,但随着时间的推移,其局限性也日益凸
昆仑天工- Go社招 - 二面 技术+业务 - 7.10
huaxinjiayou
java
小米硬件提前批小米硬件提前批电池方向笔试题是什么内容?求问各位大神!#牛客在线求职答疑中心#嵌入式linux走Qt好还是驱动好有没有大佬能给点建议目前摆在面前两条路不知道走哪个比较好本人刚写完cpp想走qt开发但是看现在租房求助!请问上海中山公园地铁站#租房前辈的忠告##毕业租房也有小确幸#这块有房东直租吗#非技术投递记录(38571)#绝友#非技术投递记录#绝友塔游戏6.28投递7.1笑死,直接
破解电脑密码
gg168888
破解 windows 工具 审查 文档 网络
开机密码是我们最先要遇到的因此我们就先从CMOS密码破解讲起。虽然CMOS种类各异,但它们的加密方法却基本一致。一般破解的方法主要从"硬"和"软"两个方面来进行。一、CMOS破解使用电脑,首先需要开机。因此开机密码是我们最先要遇到的。虽然CMOS种类各异,但它们的加密方法却基本一致。一般破解的方法主要从"硬"和"软"两个方面来进行。1."硬"解除方法硬件方法解除CMOS密码原理是将主板上的CMOS
算法 单链的创建与删除
换个号韩国红果果
c 算法
先创建结构体
struct student {
int data;
//int tag;//标记这是第几个
struct student *next;
};
// addone 用于将一个数插入已从小到大排好序的链中
struct student *addone(struct student *h,int x){
if(h==NULL) //??????
《大型网站系统与Java中间件实践》第2章读后感
白糖_
java中间件
断断续续花了两天时间试读了《大型网站系统与Java中间件实践》的第2章,这章总述了从一个小型单机构建的网站发展到大型网站的演化过程---整个过程会遇到很多困难,但每一个屏障都会有解决方案,最终就是依靠这些个解决方案汇聚到一起组成了一个健壮稳定高效的大型系统。
看完整章内容,
zeus持久层spring事务单元测试
deng520159
java DAO spring jdbc
今天把zeus事务单元测试放出来,让大家指出他的毛病,
1.ZeusTransactionTest.java 单元测试
package com.dengliang.zeus.webdemo.test;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import
Rss 订阅 开发
周凡杨
html xml 订阅 rss 规范
RSS是 Really Simple Syndication的缩写(对rss2.0而言,是这三个词的缩写,对rss1.0而言则是RDF Site Summary的缩写,1.0与2.0走的是两个体系)。
RSS
分页查询实现
g21121
分页查询
在查询列表时我们常常会用到分页,分页的好处就是减少数据交换,每次查询一定数量减少数据库压力等等。
按实现形式分前台分页和服务器分页:
前台分页就是一次查询出所有记录,在页面中用js进行虚拟分页,这种形式在数据量较小时优势比较明显,一次加载就不必再访问服务器了,但当数据量较大时会对页面造成压力,传输速度也会大幅下降。
服务器分页就是每次请求相同数量记录,按一定规则排序,每次取一定序号直接的数据
spring jms异步消息处理
510888780
jms
spring JMS对于异步消息处理基本上只需配置下就能进行高效的处理。其核心就是消息侦听器容器,常用的类就是DefaultMessageListenerContainer。该容器可配置侦听器的并发数量,以及配合MessageListenerAdapter使用消息驱动POJO进行消息处理。且消息驱动POJO是放入TaskExecutor中进行处理,进一步提高性能,减少侦听器的阻塞。具体配置如下:
highCharts柱状图
布衣凌宇
hightCharts 柱图
第一步:导入 exporting.js,grid.js,highcharts.js;第二步:写controller
@Controller@RequestMapping(value="${adminPath}/statistick")public class StatistickController { private UserServi
我的spring学习笔记2-IoC(反向控制 依赖注入)
aijuans
spring mvc Spring 教程 spring3 教程 Spring 入门
IoC(反向控制 依赖注入)这是Spring提出来了,这也是Spring一大特色。这里我不用多说,我们看Spring教程就可以了解。当然我们不用Spring也可以用IoC,下面我将介绍不用Spring的IoC。
IoC不是框架,她是java的技术,如今大多数轻量级的容器都会用到IoC技术。这里我就用一个例子来说明:
如:程序中有 Mysql.calss 、Oracle.class 、SqlSe
TLS java简单实现
antlove
java ssl keystore tls secure
1. SSLServer.java
package ssl;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.KeyStore;
import
Zip解压压缩文件
百合不是茶
Zip格式解压 Zip流的使用 文件解压
ZIP文件的解压缩实质上就是从输入流中读取数据。Java.util.zip包提供了类ZipInputStream来读取ZIP文件,下面的代码段创建了一个输入流来读取ZIP格式的文件;
ZipInputStream in = new ZipInputStream(new FileInputStream(zipFileName));
&n
underscore.js 学习(一)
bijian1013
JavaScript underscore
工作中需要用到underscore.js,发现这是一个包括了很多基本功能函数的js库,里面有很多实用的函数。而且它没有扩展 javascript的原生对象。主要涉及对Collection、Object、Array、Function的操作。 学
java jvm常用命令工具——jstatd命令(Java Statistics Monitoring Daemon)
bijian1013
java jvm jstatd
1.介绍
jstatd是一个基于RMI(Remove Method Invocation)的服务程序,它用于监控基于HotSpot的JVM中资源的创建及销毁,并且提供了一个远程接口允许远程的监控工具连接到本地的JVM执行命令。
jstatd是基于RMI的,所以在运行jstatd的服务
【Spring框架三】Spring常用注解之Transactional
bit1129
transactional
Spring可以通过注解@Transactional来为业务逻辑层的方法(调用DAO完成持久化动作)添加事务能力,如下是@Transactional注解的定义:
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version
我(程序员)的前进方向
bitray
程序员
作为一个普通的程序员,我一直游走在java语言中,java也确实让我有了很多的体会.不过随着学习的深入,java语言的新技术产生的越来越多,从最初期的javase,我逐渐开始转变到ssh,ssi,这种主流的码农,.过了几天为了解决新问题,webservice的大旗也被我祭出来了,又过了些日子jms架构的activemq也开始必须学习了.再后来开始了一系列技术学习,osgi,restful.....
nginx lua开发经验总结
ronin47
使用nginx lua已经两三个月了,项目接开发完毕了,这几天准备上线并且跟高德地图对接。回顾下来lua在项目中占得必中还是比较大的,跟PHP的占比差不多持平了,因此在开发中遇到一些问题备忘一下 1:content_by_lua中代码容量有限制,一般不要写太多代码,正常编写代码一般在100行左右(具体容量没有细心测哈哈,在4kb左右),如果超出了则重启nginx的时候会报 too long pa
java-66-用递归颠倒一个栈。例如输入栈{1,2,3,4,5},1在栈顶。颠倒之后的栈为{5,4,3,2,1},5处在栈顶
bylijinnan
java
import java.util.Stack;
public class ReverseStackRecursive {
/**
* Q 66.颠倒栈。
* 题目:用递归颠倒一个栈。例如输入栈{1,2,3,4,5},1在栈顶。
* 颠倒之后的栈为{5,4,3,2,1},5处在栈顶。
*1. Pop the top element
*2. Revers
正确理解Linux内存占用过高的问题
cfyme
linux
Linux开机后,使用top命令查看,4G物理内存发现已使用的多大3.2G,占用率高达80%以上:
Mem: 3889836k total, 3341868k used, 547968k free, 286044k buffers
Swap: 6127608k total,&nb
[JWFD开源工作流]当前流程引擎设计的一个急需解决的问题
comsci
工作流
当我们的流程引擎进入IRC阶段的时候,当循环反馈模型出现之后,每次循环都会导致一大堆节点内存数据残留在系统内存中,循环的次数越多,这些残留数据将导致系统内存溢出,并使得引擎崩溃。。。。。。
而解决办法就是利用汇编语言或者其它系统编程语言,在引擎运行时,把这些残留数据清除掉。
自定义类的equals函数
dai_lm
equals
仅作笔记使用
public class VectorQueue {
private final Vector<VectorItem> queue;
private class VectorItem {
private final Object item;
private final int quantity;
public VectorI
Linux下安装R语言
datageek
R语言 linux
命令如下:sudo gedit /etc/apt/sources.list1、deb http://mirrors.ustc.edu.cn/CRAN/bin/linux/ubuntu/ precise/ 2、deb http://dk.archive.ubuntu.com/ubuntu hardy universesudo apt-key adv --keyserver ke
如何修改mysql 并发数(连接数)最大值
dcj3sjt126com
mysql
MySQL的连接数最大值跟MySQL没关系,主要看系统和业务逻辑了
方法一:进入MYSQL安装目录 打开MYSQL配置文件 my.ini 或 my.cnf查找 max_connections=100 修改为 max_connections=1000 服务里重起MYSQL即可
方法二:MySQL的最大连接数默认是100客户端登录:mysql -uusername -ppass
单一功能原则
dcj3sjt126com
面向对象的程序设计 软件设计 编程原则
单一功能原则[
编辑]
SOLID 原则
单一功能原则
开闭原则
Liskov代换原则
接口隔离原则
依赖反转原则
查
论
编
在面向对象编程领域中,单一功能原则(Single responsibility principle)规定每个类都应该有
POJO、VO和JavaBean区别和联系
fanmingxing
VO POJO javabean
POJO和JavaBean是我们常见的两个关键字,一般容易混淆,POJO全称是Plain Ordinary Java Object / Plain Old Java Object,中文可以翻译成:普通Java类,具有一部分getter/setter方法的那种类就可以称作POJO,但是JavaBean则比POJO复杂很多,JavaBean是一种组件技术,就好像你做了一个扳子,而这个扳子会在很多地方被
SpringSecurity3.X--LDAP:AD配置
hanqunfeng
SpringSecurity
前面介绍过基于本地数据库验证的方式,参考http://hanqunfeng.iteye.com/blog/1155226,这里说一下如何修改为使用AD进行身份验证【只对用户名和密码进行验证,权限依旧存储在本地数据库中】。
将配置文件中的如下部分删除:
<!-- 认证管理器,使用自定义的UserDetailsService,并对密码采用md5加密-->
mac mysql 修改密码
IXHONG
mysql
$ sudo /usr/local/mysql/bin/mysqld_safe –user=root & //启动MySQL(也可以通过偏好设置面板来启动)$ sudo /usr/local/mysql/bin/mysqladmin -uroot password yourpassword //设置MySQL密码(注意,这是第一次MySQL密码为空的时候的设置命令,如果是修改密码,还需在-
设计模式--抽象工厂模式
kerryg
设计模式
抽象工厂模式:
工厂模式有一个问题就是,类的创建依赖于工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则。我们采用抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。
总结:这个模式的好处就是,如果想增加一个功能,就需要做一个实现类,
评"高中女生军训期跳楼”
nannan408
首先,先抛出我的观点,各位看官少点砖头。那就是,中国的差异化教育必须做起来。
孔圣人有云:有教无类。不同类型的人,都应该有对应的教育方法。目前中国的一体化教育,不知道已经扼杀了多少创造性人才。我们出不了爱迪生,出不了爱因斯坦,很大原因,是我们的培养思路错了,我们是第一要“顺从”。如果不顺从,我们的学校,就会用各种方法,罚站,罚写作业,各种罚。军
scala如何读取和写入文件内容?
qindongliang1922
java jvm scala
直接看如下代码:
package file
import java.io.RandomAccessFile
import java.nio.charset.Charset
import scala.io.Source
import scala.reflect.io.{File, Path}
/**
* Created by qindongliang on 2015/
C语言算法之百元买百鸡
qiufeihu
c 算法
中国古代数学家张丘建在他的《算经》中提出了一个著名的“百钱买百鸡问题”,鸡翁一,值钱五,鸡母一,值钱三,鸡雏三,值钱一,百钱买百鸡,问翁,母,雏各几何?
代码如下:
#include <stdio.h>
int main()
{
int cock,hen,chick; /*定义变量为基本整型*/
for(coc
Hadoop集群安全性:Hadoop中Namenode单点故障的解决方案及详细介绍AvatarNode
wyz2009107220
NameNode
正如大家所知,NameNode在Hadoop系统中存在单点故障问题,这个对于标榜高可用性的Hadoop来说一直是个软肋。本文讨论一下为了解决这个问题而存在的几个solution。
1. Secondary NameNode
原理:Secondary NN会定期的从NN中读取editlog,与自己存储的Image进行合并形成新的metadata image
优点:Hadoop较早的版本都自带,