chrome-base 如何实现一个BindOnce
考虑一个问题:
worker_thread.task_runner()->PostDelayedTask(FROM_HERE, base::BindOnce(&Ref::Foo, ref, 1), base::Milliseconds(1000));
BindOnce 是如何实现的呢?
翻看源码:base\functional\bind.h
写的 非常简洁
// Bind as OnceCallback.
template <typename Functor, typename... Args>
inline OnceCallback<internal::MakeUnboundRunType<Functor, Args...>> BindOnce(Functor&& functor,Args&&... args) {static_assert(!internal::IsOnceCallback<std::decay_t<Functor>>() ||(std::is_rvalue_reference<Functor&&>() &&!std::is_const<std::remove_reference_t<Functor>>()),"BindOnce requires non-const rvalue for OnceCallback binding."" I.e.: base::BindOnce(std::move(callback)).");static_assert(std::conjunction<internal::AssertBindArgIsNotBasePassed<std::decay_t<Args>>...>::value,"Use std::move() instead of base::Passed() with base::BindOnce()");return internal::BindImpl<OnceCallback>(std::forward<Functor>(functor),std::forward<Args>(args)...);
}
重要的也就是最后一句:构造一个BindImpl,同时完美转发
internal::BindImpl<OnceCallback>(std::forward<Functor>(functor),std::forward<Args>(args)...)
base\functional\bind_internal.h
template <template <typename> class CallbackT,typename Functor,typename... Args>
decltype(auto) BindImpl(Functor&& functor, Args&&... args) {// This block checks if each |args| matches to the corresponding params of the// target function. This check does not affect the behavior of Bind, but its// error message should be more readable.static constexpr bool kIsOnce = IsOnceCallback<CallbackT<void()>>::value;using Helper = BindTypeHelper<Functor, Args...>;using FunctorTraits = typename Helper::FunctorTraits;using BoundArgsList = typename Helper::BoundArgsList;using UnwrappedArgsList =MakeUnwrappedTypeList<kIsOnce, FunctorTraits::is_method, Args&&...>;using BoundParamsList = typename Helper::BoundParamsList;static_assert(MakeFunctorTraits<Functor>::is_stateless,"Capturing lambdas and stateful lambdas are intentionally not supported. ""Please use base::Bind{Once,Repeating} directly to bind arguments.");static_assert(AssertBindArgsValidity<std::make_index_sequence<Helper::num_bounds>,BoundArgsList, UnwrappedArgsList,BoundParamsList>::ok,"The bound args need to be convertible to the target params.");using BindState = MakeBindStateType<Functor, Args...>;using UnboundRunType = MakeUnboundRunType<Functor, Args...>;using Invoker = Invoker<BindState, UnboundRunType>;using CallbackType = CallbackT<UnboundRunType>;// Store the invoke func into PolymorphicInvoke before casting it to// InvokeFuncStorage, so that we can ensure its type matches to// PolymorphicInvoke, to which CallbackType will cast back.using PolymorphicInvoke = typename CallbackType::PolymorphicInvoke;PolymorphicInvoke invoke_func;if constexpr (kIsOnce) {invoke_func = Invoker::RunOnce;} else {invoke_func = Invoker::Run;}using InvokeFuncStorage = BindStateBase::InvokeFuncStorage;return CallbackType(BindState::Create(reinterpret_cast<InvokeFuncStorage>(invoke_func),std::forward<Functor>(functor), std::forward<Args>(args)...));
}
BindState的实现
// This stores all the state passed into Bind().
template <typename Functor, typename... BoundArgs>
struct BindState final : BindStateBase {using IsCancellable = std::bool_constant<CallbackCancellationTraits<Functor,std::tuple<BoundArgs...>>::is_cancellable>;template <typename ForwardFunctor, typename... ForwardBoundArgs>static BindState* Create(BindStateBase::InvokeFuncStorage invoke_func,ForwardFunctor&& functor,ForwardBoundArgs&&... bound_args) {// Ban ref counted receivers that were not yet fully constructed to avoid// a common pattern of racy situation.BanUnconstructedRefCountedReceiver<ForwardFunctor>(bound_args...);// IsCancellable is std::false_type if// CallbackCancellationTraits<>::IsCancelled returns always false.// Otherwise, it's std::true_type.return new BindState(IsCancellable{}, invoke_func,std::forward<ForwardFunctor>(functor),std::forward<ForwardBoundArgs>(bound_args)...);}Functor functor_;std::tuple<BoundArgs...> bound_args_;private:static constexpr bool is_nested_callback =MakeFunctorTraits<Functor>::is_callback;template <typename ForwardFunctor, typename... ForwardBoundArgs>explicit BindState(std::true_type,BindStateBase::InvokeFuncStorage invoke_func,ForwardFunctor&& functor,ForwardBoundArgs&&... bound_args): BindStateBase(invoke_func,&Destroy,&QueryCancellationTraits<BindState>),functor_(std::forward<ForwardFunctor>(functor)),bound_args_(std::forward<ForwardBoundArgs>(bound_args)...) {// We check the validity of nested callbacks (e.g., Bind(callback, ...)) in// release builds to avoid null pointers from ending up in posted tasks,// causing hard-to-diagnose crashes. Ideally we'd do this for all functors// here, but that would have a large binary size impact.if (is_nested_callback) {CHECK(!IsNull(functor_));} else {DCHECK(!IsNull(functor_));}}template <typename ForwardFunctor, typename... ForwardBoundArgs>explicit BindState(std::false_type,BindStateBase::InvokeFuncStorage invoke_func,ForwardFunctor&& functor,ForwardBoundArgs&&... bound_args): BindStateBase(invoke_func, &Destroy),functor_(std::forward<ForwardFunctor>(functor)),bound_args_(std::forward<ForwardBoundArgs>(bound_args)...) {// See above for CHECK/DCHECK rationale.if (is_nested_callback) {CHECK(!IsNull(functor_));} else {DCHECK(!IsNull(functor_));}}~BindState() = default;static void Destroy(const BindStateBase* self) {delete static_cast<const BindState*>(self);}
};
其中有两个成员变量:
Functor functor_;std::tuple<BoundArgs...> bound_args_;
其中用到了std::tuple ??
为什么chromium不使用std::bind
相对于std::bind, base::Bind能够帮助我们减少生命周期缺陷:
在使用 base::BindOnce() 方法产生一个 base::OnceClosure 的时候,一般会传递一个 base::WeakPrt,而不是一个裸指针。base::WeakPrt能确保所指向的对象销毁时,绑定在对象上的回调能被取消。否则一般会产生一个段错误。
如果声明裸指针则必须使用Unretained符号。
chromium bind出现的更早,且通过BindOnce与BindRepeating 对生命周期做了更加细致的区分,C++ 14之后好像也有了类似的bind?
c++中的元组
元组基本使用
https://en.cppreference.com/w/cpp/utility/tuple/get c11中引入了 std::tuple,并在后续的c14中扩充了使用方式
#include <iostream>
#include <string>
#include <tuple>int main()
{auto t = std::make_tuple(1, "Foo", 3.14);// index-based accessstd::cout << "(" << std::get<0>(t) << ", " << std::get<1>(t)<< ", " << std::get<2>(t) << ")\n";// type-based access (C++14 or later)std::cout << "(" << std::get<int>(t) << ", " << std::get<const char*>(t)<< ", " << std::get<double>(t) << ")\n";// Note: std::tie and structured binding may also be used to decompose a tuple
}
元组用作函数参数
#include <iostream>
#include <string>
#include <tuple>void foo(int a1, const char* a2, double a3) {// Do somethingstd::cout << a1 << std::endl;std::cout << a2 << std::endl;std::cout << a3 << std::endl;
}int main() {auto t = std::make_tuple(1, "Foo", 3.14);foo(std::get<0>(t), std::get<1>(t), std::get<2>(t));return 0;
}
观察后会发现,配合c++11的可变参数模板,可以写出这样一个函数,整体如下:
https://zhuanlan.zhihu.com/p/465077081
#include <iostream>
#include <string>
#include <tuple>void foo(int a1, const char* a2, double a3) {// Do somethingstd::cout << a1 << std::endl;std::cout << a2 << std::endl;std::cout << a3 << std::endl;
}template <typename F, typename T, std::size_t... I>
void bar(F f, const T& t) {f(std::get<I>(t)...);
}// 或者这样定义也可以
template <std::size_t... I, typename F, typename T>
void bar2(F f, const T& t) {f(std::get<I>(t)...);
}int main() {auto t = std::make_tuple(1, "Foo", 3.14);//foo(std::get<0>(t), std::get<1>(t), std::get<2>(t));bar<decltype(foo), decltype(t), 0, 1, 2>(foo, t);// 少了函数类型和调用类型的模板,这里编译器帮我们做了类型推导bar2<0, 1, 2>(foo, t);return 0;
}
使用std::index_sequence
上述调用方式比较笨拙,不够优雅灵活,还需要手动写模板参数,其实看看0,1,2的序列,其实是从0到N-1的整数序列,c++14中正好提供了生成这种序列的机制:std::index_sequence,这里面有一系列的序列别名,我们这里更简便的使用index_sequence就能解决问题了,具体如下
https://zhuanlan.zhihu.com/p/490967621
/// Alias template index_sequencetemplate<size_t... _Idx>using index_sequence = integer_sequence<size_t, _Idx...>;/// Alias template make_index_sequencetemplate<size_t _Num>using make_index_sequence = make_integer_sequence<size_t, _Num>;/// Alias template index_sequence_fortemplate<typename... _Types>using index_sequence_for = make_index_sequence<sizeof...(_Types)>;
有了这个基础设施以后我们就可以这样写代码了:
https://blog.csdn.net/qq_51986723/article/details/127602490 std::index_sequence如何使用
#include <iostream>
#include <string>
#include <tuple>void foo(int a1, const char* a2, double a3) {// Do somethingstd::cout << a1 << std::endl;std::cout << a2 << std::endl;std::cout << a3 << std::endl;
}template <typename F, typename T, std::size_t... I>
void barImpl(F f, const T& t, std::index_sequence<I...>) {f(std::get<I>(t)...);
}template<typename F, typename T>
void bar(F f, const T& t) {barImpl(f, t, std::make_index_sequence<std::tuple_size<T>::value>());
}int main() {auto t = std::make_tuple(1, "Foo", 3.14);bar<decltype(foo), decltype(t)>(foo, t);return 0;
}
增加返回值
上面的虽然写起来比较简单了,但是没有返回值,我们可以采用decltype特性来解决。
#include <iostream>
#include <string>
#include <tuple>void foo(int a1, const char* a2, double a3) {// Do somethingstd::cout << a1 << std::endl;std::cout << a2 << std::endl;std::cout << a3 << std::endl;
}template <typename F, typename T, std::size_t... I>
auto barImpl(F f, const T& t, std::index_sequence<I...>) -> decltype(f(std::get<I>(t)...)){return f(std::get<I>(t)...);
}template<typename F, typename T>
auto bar(F f, const T& t) -> decltype(barImpl(f, t, std::make_index_sequence<std::tuple_size<T>::value>())) {return barImpl(f, t, std::make_index_sequence<std::tuple_size<T>::value>());
}
int main() {auto t = std::make_tuple(1, "Foo", 3.14);bar<decltype(foo), decltype(t)>(foo, t);return 0;
这样就使用任意的函数调用了,包括带返回值的和不带返回值的。
最终版本
-
封装一个万能调用类 +
-
直接传参
-
完美转发
将调用函数及参数封装进类中,在需要的时候调用Run一下就好了。
#include <iostream>
#include <string>
#include <tuple>template <typename Functor, typename... BoundArgs>
class OnceCallBack {
private:template <typename Functor1, typename TupleType1, std::size_t... I1>static auto RunImpl(Functor1 f, const TupleType1& t, std::index_sequence<I1...>) -> decltype(f(std::get<I1>(t)...)) {return f(std::get<I1>(t)...);}Functor* f_;std::tuple<BoundArgs...> t_;
public:OnceCallBack(Functor&& f, BoundArgs&&... t): f_(std::forward<Functor>(f)), t_(std::forward<BoundArgs>(t)...) {}auto Run() -> decltype(RunImpl(f_, t_, std::make_index_sequence<std::tuple_size<std::tuple<BoundArgs...>>::value>())) {return RunImpl(f_, t_, std::make_index_sequence<std::tuple_size<std::tuple<BoundArgs...>>::value>());}
};double foo_ret(double a1, char a2, const char* a3) {// Do somethingstd::cout << a1 << std::endl;std::cout << a2 << std::endl;std::cout << a3 << std::endl;return 1.2;
}int main() {// 函数模板参数类型编译器可以推导,但是类不行,所以这里需要很繁琐的传递参数类型OnceCallBack<decltype(foo_ret), decltype(1.0), decltype('c'), decltype("this is my test")> callback(std::move(foo_ret), 1.0, 'c', "this is my test");std::cout << callback.Run() << std::endl;
}
到这里,是不是已经很熟悉了。至此,一个最简单的base::Bind 方法就算实现完成了。
Chromium中的base::Bind
chromium中除了OnceCallBack还有RepeatingCallback,另外考虑的各种对象的生命周期问题,这样就涉及到指针传递,所以做的更为复杂,主要涉及的类包括:
-
BindStateBase
-
BindState
-
OnceCallBack
-
RepeatingCallback
-
Invoker
-
UnWrap
看到的也就是开头看到的源码
std::bind
C++11 bind绑定器,是一个函数模板 ,可以自动推演模板类型参数=> 返回的结果还是一个函数对象
bind占位符最多有20个参数
#include <iostream>
#include <typeinfo>
#include <string>
#include <memory>
#include <vector>
#include <functional>
#include <thread>
using namespace std;
using namespace placeholders;/*
C++11 bind绑定器 => 返回的结果还是一个函数对象
*/void hello(string str) { cout << str << endl; }
int sum(int a, int b) { return a + b; }
class Test
{
public:int sum(int a, int b) { return a + b; }
};
int main()
{//bind是函数模板 可以自动推演模板类型参数bind(hello, "hello bind!")();//返回的结果是绑定器,也就是函数对象 最后一个()表示调用函数对象的operator() cout << bind(sum, 10, 20)() << endl;cout << bind(&Test::sum, Test(), 20, 30)() << endl;//参数占位符 绑定器出了语句,无法继续使用//只是占位的作用,调用的时候就要传递参数了 //书写的时候使用多少个占位符,就是意味着用户调用的时候要传入几个参数bind(hello, placeholders::_1)("hello bind 2!");cout << bind(sum, placeholders::_1, placeholders::_2)(200, 300) << endl;//此处把bind返回的绑定器binder就复用起来了function<void(string)> func1 = bind(hello, _1);func1("hello china!");func1("hello shan xi!");func1("hello si chuan!");return 0;
}
/*** @brief Function template for std::bind.* @ingroup binders*/template<typename _Func, typename... _BoundArgs>inline typename_Bind_helper<__is_socketlike<_Func>::value, _Func, _BoundArgs...>::typebind(_Func&& __f, _BoundArgs&&... __args){typedef _Bind_helper<false, _Func, _BoundArgs...> __helper_type;return typename __helper_type::type(std::forward<_Func>(__f),std::forward<_BoundArgs>(__args)...);}
---------------------------------------------------------------------------------------------------------------template<bool _SocketLike, typename _Func, typename... _BoundArgs>struct _Bind_helper: _Bind_check_arity<typename decay<_Func>::type, _BoundArgs...>{typedef typename decay<_Func>::type __func_type;typedef _Bind<__func_type(typename decay<_BoundArgs>::type...)> type;};
--------------------------------------------------template<typename _Functor, typename... _Bound_args>class _Bind<_Functor(_Bound_args...)>: public _Weak_result_type<_Functor>{typedef typename _Build_index_tuple<sizeof...(_Bound_args)>::__type_Bound_indexes;_Functor _M_f;tuple<_Bound_args...> _M_bound_args;// Call unqualifiedtemplate<typename _Result, typename... _Args, std::size_t... _Indexes>_Result__call(tuple<_Args...>&& __args, _Index_tuple<_Indexes...>){return std::__invoke(_M_f,_Mu<_Bound_args>()(std::get<_Indexes>(_M_bound_args), __args)...);}// Call as consttemplate<typename _Result, typename... _Args, std::size_t... _Indexes>_Result__call_c(tuple<_Args...>&& __args, _Index_tuple<_Indexes...>) const{return std::__invoke(_M_f,_Mu<_Bound_args>()(std::get<_Indexes>(_M_bound_args), __args)...);}// Call as volatiletemplate<typename _Result, typename... _Args, std::size_t... _Indexes>_Result__call_v(tuple<_Args...>&& __args,_Index_tuple<_Indexes...>) volatile{return std::__invoke(_M_f,_Mu<_Bound_args>()(__volget<_Indexes>(_M_bound_args), __args)...);}// Call as const volatiletemplate<typename _Result, typename... _Args, std::size_t... _Indexes>_Result__call_c_v(tuple<_Args...>&& __args,_Index_tuple<_Indexes...>) const volatile{return std::__invoke(_M_f,_Mu<_Bound_args>()(__volget<_Indexes>(_M_bound_args), __args)...);}template<typename _BoundArg, typename _CallArgs>using _Mu_type = decltype(_Mu<typename remove_cv<_BoundArg>::type>()(std::declval<_BoundArg&>(), std::declval<_CallArgs&>()) );template<typename _Fn, typename _CallArgs, typename... _BArgs>using _Res_type_impl= typename result_of< _Fn&(_Mu_type<_BArgs, _CallArgs>&&...) >::type;template<typename _CallArgs>using _Res_type = _Res_type_impl<_Functor, _CallArgs, _Bound_args...>;template<typename _CallArgs>using __dependent = typenameenable_if<bool(tuple_size<_CallArgs>::value+1), _Functor>::type;template<typename _CallArgs, template<class> class __cv_quals>using _Res_type_cv = _Res_type_impl<typename __cv_quals<__dependent<_CallArgs>>::type,_CallArgs,typename __cv_quals<_Bound_args>::type...>;public:template<typename... _Args>explicit _Bind(const _Functor& __f, _Args&&... __args): _M_f(__f), _M_bound_args(std::forward<_Args>(__args)...){ }template<typename... _Args>explicit _Bind(_Functor&& __f, _Args&&... __args): _M_f(std::move(__f)), _M_bound_args(std::forward<_Args>(__args)...){ }_Bind(const _Bind&) = default;_Bind(_Bind&& __b): _M_f(std::move(__b._M_f)), _M_bound_args(std::move(__b._M_bound_args)){ }// Call unqualifiedtemplate<typename... _Args,typename _Result = _Res_type<tuple<_Args...>>>_Resultoperator()(_Args&&... __args){return this->__call<_Result>(std::forward_as_tuple(std::forward<_Args>(__args)...),_Bound_indexes());}// Call as consttemplate<typename... _Args,typename _Result = _Res_type_cv<tuple<_Args...>, add_const>>_Resultoperator()(_Args&&... __args) const{return this->__call_c<_Result>(std::forward_as_tuple(std::forward<_Args>(__args)...),_Bound_indexes());}#if __cplusplus > 201402L
# define _GLIBCXX_DEPR_BIND \[[deprecated("std::bind does not support volatile in C++17")]]
#else
# define _GLIBCXX_DEPR_BIND
#endif// Call as volatiletemplate<typename... _Args,typename _Result = _Res_type_cv<tuple<_Args...>, add_volatile>>_GLIBCXX_DEPR_BIND_Resultoperator()(_Args&&... __args) volatile{return this->__call_v<_Result>(std::forward_as_tuple(std::forward<_Args>(__args)...),_Bound_indexes());}// Call as const volatiletemplate<typename... _Args,typename _Result = _Res_type_cv<tuple<_Args...>, add_cv>>_GLIBCXX_DEPR_BIND_Resultoperator()(_Args&&... __args) const volatile{return this->__call_c_v<_Result>(std::forward_as_tuple(std::forward<_Args>(__args)...),_Bound_indexes());}};
placeholders 占位符:最多支持20个
相关文章:
chrome-base 如何实现一个BindOnce
考虑一个问题: worker_thread.task_runner()->PostDelayedTask(FROM_HERE, base::BindOnce(&Ref::Foo, ref, 1), base::Milliseconds(1000)); BindOnce 是如何实现的呢? 翻看源码:base\functional\bind.h 写的 非常简洁 // Bind a…...
HTML学习之CSS三种引入方式
HTML学习之CSS三种引入方式 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title>…...
Mysql基于binlog主从同步配置
主配置: 修改配置文件:/etc/my.cnf 添加server-id1 重启MySQL服务:systemctl restart mysqld 创建用户并授权: mysql> create user rep192.168.79.% identified with mysql_native_password by 123456; Query OK, 0 rows aff…...
Docker Desktop安装到其他盘
Docker Desktop 默认安装到c盘,占用空间太大了,想给安装到其他盘,网上找了半天的都不对 正确安装命令: start /w "" "Docker Desktop Installer.exe" install --installation-dirF:\docker命令执行成功&am…...
NetCore Consul动态伸缩+Ocelot 网关 缓存 自定义缓存 + 限流、熔断、超时 等服务治理
网关 OcelotGeteway 网关 Ocelot配置文件 {//单地址多实例负载均衡Consul 实现动态伸缩"Routes": [{// 上游 》》 接受的请求//上游请求方法,可以设置特定的 HTTP 方法列表或设置空列表以允许其中任何方法"UpstreamHttpMethod": [ "Get", &quo…...
ubuntu 本地部署deepseek r1 蒸馏模型
本文中的文件路径或网络代理需要根据自身环境自行删改 一、交互式chat页面 1.1 open-webui 交互窗口部署:基于docker安装,且支持联网搜索 Open WebUI 是一个可扩展、功能丰富且用户友好的自托管 AI 平台,旨在完全离线操作。它支持各种 LLM…...
go语言中的反射
为什么会引入反射 有时我们需要写一个函数,这个函数有能力统一处理各种值类型,而这些类型可能无法共享同一个接口,也可能布局未知,也有可能这个类型在我们设计函数时还不存在,这个时候我们就可以用到反射。 空接口可…...
旅行社项目展示微信小程序功能模块和开发流程
旅行社当前旅游线路的程序(微信小程序),旨在帮助旅行社更高效地管理线下活动预订,同时为客户提供便捷的报名和查看功能。适用于短途游、团队建设等活动,支持在线预订、缴费及订单管理,可根据用户需求定制更多个性化服务,为公司提升品牌知名度与客户体验。通过简洁明了的…...
JUC学习笔记02
文章目录 JUC笔记2练习题:手写线程池代码解释:AdvancedThreadPool 类:WorkerThread 内部类:AdvancedThreadPoolExample 类: 线程池的思考CPU密集型IO密集型 练习题:手写自动重试机练习题:手写定…...
【论文翻译】DeepSeek-V3论文翻译——DeepSeek-V3 Technical Report——第一部分:引言与模型架构
论文原文链接:DeepSeek-V3/DeepSeek_V3.pdf at main deepseek-ai/DeepSeek-V3 GitHub 特别声明,本文不做任何商业用途,仅作为个人学习相关论文的翻译记录。本文对原文内容直译,一切以论文原文内容为准,对原文作者表示…...
python编程-类结构,lambda语法,原始字符串
一个类的基本结构包括以下部分: 类名:用来描述具有相同属性和方法的对象的集合。 属性:类变量或实例变量,用于处理类及其实例对象的相关数据。 方法:在类中定义的函数,用于执行特定操作。 构造器ÿ…...
C++:代码常见规范1
头文件包含 (1)先系统头文件,后用户头文件:这是一个良好的编程习惯。系统头文件通常包含标准库的定义,而用户头文件则包含项目特定的定义。将系统头文件放在前面可以避免因用户头文件中的定义与系统头文件冲突而导致的问题。 #include <…...
C++(进阶五)--STL--用一颗红黑树封装map和set
目录 1.红黑树源码(简略版) 2.模板参数的控制 3.红黑树的结点 4.迭代器的实现 正向迭代器 反向迭代器 5.set的模拟实现 6.map的模拟实现 7.封装完成后的代码 RBTree.h mymap.h myset.h 1.红黑树源码(简略版) 下面我们…...
DeepSeek服务器繁忙问题的原因分析与解决方案
一、引言 随着人工智能技术的飞速发展,DeepSeek 等语言模型在众多领域得到了广泛应用。然而,在春节这段时间的使用过程中,用户常常遭遇服务器繁忙的问题,这不仅影响了用户的使用体验,也在一定程度上限制了模型的推广和…...
《手札·开源篇》数字化转型助力永磁电机企业降本增效:快速设计软件如何让研发效率提升40%?
数字化转型助力永磁电机企业降本增效:快速设计软件如何让研发效率提升40%? 一、痛点:传统研发模式正在吃掉企业的利润 永磁电机行业面临两大挑战: 研发周期长:一款新电机从设计到量产需6-12个月,电磁计算…...
飞算JavaAI :AI + 时代下的行业趋势引领者与推动者
在科技飞速发展的当下,AI 时代正以前所未有的速度重塑着各个行业的格局,而软件开发领域更是这场变革的前沿阵地。在众多创新力量之中,飞算JavaAI 脱颖而出,宛如一颗璀璨的新星,凭借其独树一帜的特性与强大功能&#x…...
【重新认识C语言----结构体篇】
目录 -----------------------------------------begin------------------------------------- 引言 1. 结构体的基本概念 1.1 为什么需要结构体? 1.2 结构体的定义 2. 结构体变量的声明与初始化 2.1 声明结构体变量 2.2 初始化结构体变量 3. 结构体成员的访…...
解决错误:CondaHTTPError: HTTP 000 CONNECTION FAILED for url
解决错误:CondaHTTPError: HTTP 000 CONNECTION FAILED for url 查看channels:vim ~/.condarcshow_channel_urls: true channels:- http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/- http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/msys2/…...
使用令牌桶算法通过redis实现限流
令牌桶算法是一种常用的限流算法,它可以平滑地控制请求的处理速率。在 Java 中结合 Redis 实现令牌桶算法,可以利用 Redis 的原子操作来保证多节点环境下的限流效果。 一 实现思路 初始化令牌桶:在 Redis 中存储令牌桶的相关信息࿰…...
Docker的进程和Cgroup概念
Docker的进程和Cgroup概念 容器里的进程组织或关系0号进程:containerd-shim1号进程:容器内的第一个进程进程收到信号后的三种反应两个特权信号在容器内执行 kill 命令的行为 Cgroup 介绍CPU Cgroup 中与 CFS 相关的参数Kubernetes 中的资源管理memory cg…...
Day68:类的多态
在面向对象编程(OOP)中,多态(Polymorphism)是指不同类的对象对同一消息作出响应的能力。换句话说,多态允许不同类的对象使用相同的方法名,但实现不同的行为。多态是通过继承和方法重写来实现的,通常可以分为方法重写和接口重载。 在 Python 中,多态常常通过方法重写来…...
一种解决SoC总线功能验证完备性的技术
1. 前言 通过总线将各个IP通过总线连接起来的SoC芯片是未来的大趋势,也是缩短芯片开发周期,抢先进入市场的常用方法。如何确保各个IP是否正确连接到总线上,而且各IP的地址空间分配是否正确,是一件很棘手的事情。本文提出了一种新…...
【Linux系统】线程:线程库 / 线程栈 / 线程库源码阅读学习
一、线程库 1、线程库介绍:命名与设计 命名:线程库通常根据其实现目的和平台特性进行命名。例如,POSIX标准定义了Pthreads(POSIX Threads),这是一个广泛使用的线程库规范,适用于多种操作系统。此…...
深度剖析 Redis:缓存穿透、击穿与雪崩问题及实战解决方案
一、缓存基本使用逻辑 在应用程序中,为了提高数据访问效率,常常会使用缓存。一般的缓存使用逻辑是:根据 key 去 Redis 查询是否有数据,如果命中就直接返回缓存中的数据;如果缓存不存在,则查询数据库&#…...
如何使用el-table的多选框
对el-table再次封装,使得功能更加强大! 本人在使用el-table时,因为用到分页,导致上一页勾选的数据在再次返回时,没有选中,故在原有el-table组件的基础之上再次进行了封装。 1.首先让某些不需要勾选的列表进…...
【工具变量】上市公司企业渐进式创新程度及渐进式创新锁定数据(1991-2023年)
测算方式: 参考顶刊《经济研究》孙雅慧(2024)老师的做法,用当期创新和往期创新的内容重叠度作为衡量渐进式创新程度的合理指标。通过搜集海量专利摘要,测算当前专利申请和既有专利的内容相似度,反映企业在…...
LM Studio 部署本地大语言模型
一、下载安装 1.搜索:lm studio LM Studio - Discover, download, and run local LLMs 2.下载 3.安装 4.更改成中文 二、下载模型(软件内下载) 1.选择使用代理,否则无法下载 2.更改模型下载目录 默认下载位置 C:\Users\用户名\.lmstudio\models 3.搜…...
嵌入式工程师面试经验分享与案例解析
嵌入式工程师岗位受到众多求职者的关注。面试流程严格,技术要求全面,涵盖C/C编程、数据结构与算法、操作系统、嵌入式系统开发、硬件驱动等多个方向。本文将结合真实案例,深入剖析嵌入式工程师的面试流程、常见问题及应对策略,帮助…...
英特尔至强服务器CPU销量创14年新低,AMD取得进展
过去几年是英特尔56年历史上最艰难的时期之一。该公司在晶圆代工、消费级处理器和服务器芯片等各个领域都面临困境。随着英特尔重组其晶圆代工业务,新的分析显示其服务器业务的现状和未来前景不容乐观。 英特尔最近发布的10-K文件显示:“数据中心和人工…...
判断您的Mac当前使用的是Zsh还是Bash:echo $SHELL、echo $0
要判断您的Mac当前使用的是Zsh还是Bash,可以使用以下方法: 查看默认Shell: 打开“终端”应用程序,然后输入以下命令: echo $SHELL这将显示当前默认使用的Shell。例如,如果输出是/bin/zsh,则说明您使用的是Z…...
