设计 c++ web 框架时候,想要一个框架缓存类,很多通用缓存类是用字符保存,作为框架内置就不要序列和反序列了,因为框架内部使用。
想给自己的paozhu c++ web 框架添加缓存类,参考了springboot 于是确定用单例设计模式缓存类模板。
c++11后静态变量已经统一为线程安全了,网络各种茴香豆几种吃法现在变成一种安全吃法。
因为框架时候了多线程,也要求最低c++20,所以直接使用新标准单例模式。
因为需要保存多种类型,于是设计为模版接口,这样一个通用设计 缓存模型想好了,然后就是设计类库API,需要兼容数组和单一对象。
也要有超时,于是我们确定了基础结构
struct data_cache_t
{
std::vector<BASE_TYPE> data;
unsigned int exptime = 0;
};
因为我想以后还要动态库也能使用,于是用了一个静态函数做单例
template <typename BASETYPE_T>
std::map<std::size_t, BASETYPE_T> &get_pz_cache()
{
static std::map<std::size_t, BASETYPE_T> instance;
return instance;
}
模版类需要兼顾数组和单个对象于是统一保存为vector数组,然后套入map对象,因为我们要用size_t做hash键值,这样方便统一长度。
然后根据不同api返回不同类型。
先看详细代码,后面讲一个map插入失败情况
template <typename BASE_TYPE>
class pzcache
{
private:
pzcache(){};
~pzcache(){};
pzcache(const pzcache &);
pzcache &operator=(const pzcache &);
public:
struct data_cache_t
{
std::vector<BASE_TYPE> data;
unsigned int exptime = 0;
};
public:
void save(std::size_t hashid, BASE_TYPE &data_list, int expnum = 0, bool cover_data = false)
{
std::map<std::size_t, data_cache_t> &obj = get_pz_cache<data_cache_t>();
struct data_cache_t temp;
temp.data.push_back(data_list);
if (expnum != 0)
{
temp.exptime = http::timeid() + expnum;
}
else
{
temp.exptime = 0;
}
std::unique_lock<std::mutex> lock(editlock);
auto [_, success] = obj.insert({hashid, temp});
if (!success)
{
if (cover_data)
{
obj[hashid] = temp;
}
else
{
obj[hashid].exptime = temp.exptime;
}
}
}
void save(std::size_t hashid, std::vector<BASE_TYPE> &data_list, int expnum = 0, bool cover_data = false)
{
std::map<std::size_t, data_cache_t> &obj = get_pz_cache<data_cache_t>();
struct data_cache_t temp;
temp.data = data_list;
if (expnum != 0)
{
temp.exptime = http::timeid() + expnum;
}
else
{
temp.exptime = 0;
}
std::unique_lock<std::mutex> lock(editlock);
auto [_, success] = obj.insert({hashid, temp});
if (!success)
{
if (cover_data)
{
obj[hashid] = temp;
}
else
{
obj[hashid].exptime = temp.exptime;
}
}
}
bool remove(std::size_t hashid)
{
std::map<std::size_t, data_cache_t> &obj = get_pz_cache<data_cache_t>();
std::unique_lock<std::mutex> lock(editlock);
auto iter = obj.find(hashid);
if (iter != obj.end())
{
obj.erase(iter++);
return true;
}
return false;
}
void remove_exptime()
{
std::map<std::size_t, data_cache_t> &obj = get_pz_cache<data_cache_t>();
unsigned int nowtime = http::timeid();
std::unique_lock<std::mutex> lock(editlock);
for (auto iter = obj.begin(); iter != obj.end();)
{
if (iter->second.exptime == 0)
{
continue;
}
if (iter->second.exptime < nowtime)
{
obj.erase(iter++);
}
}
}
void clear()
{
std::map<std::size_t, data_cache_t> &obj = get_pz_cache<data_cache_t>();
std::unique_lock<std::mutex> lock(editlock);
obj.clear();
}
int check(std::size_t hashid)
{
std::map<std::size_t, data_cache_t> &obj = get_pz_cache<data_cache_t>();
unsigned int nowtime = http::timeid();
std::unique_lock<std::mutex> lock(editlock);
auto iter = obj.find(hashid);
if (iter != obj.end())
{
if (iter->second.exptime == 0)
{
return 0;
}
int temp = (int)(iter->second.exptime - nowtime);
if (temp == -1)
{
return -2;
}
return temp;
}
return -1;
}
int update(std::size_t hashid, int exptime = 0)
{
std::map<std::size_t, data_cache_t> &obj = get_pz_cache<data_cache_t>();
unsigned int nowtime = http::timeid() + exptime;
if (exptime == 0)
{
nowtime = 0;
}
std::unique_lock<std::mutex> lock(editlock);
auto iter = obj.find(hashid);
if (iter != obj.end())
{
if (iter->second.exptime == 0)
{
iter->second.exptime = nowtime;
return 0;
}
iter->second.exptime = nowtime;
return 1;
}
return -1;
}
std::vector<BASE_TYPE> get_array(std::size_t hashid)
{
std::map<std::size_t, data_cache_t> &obj = get_pz_cache<data_cache_t>();
unsigned int nowtime = http::timeid();
std::unique_lock<std::mutex> lock(editlock);
auto iter = obj.find(hashid);
if (iter != obj.end())
{
if (iter->second.exptime == 0)
{
return iter->second.data;
}
if (iter->second.exptime >= nowtime)
{
return iter->second.data;
}
else
{
obj.erase(iter++);
}
}
lock.unlock();
std::vector<BASE_TYPE> temp;
return temp;
}
BASE_TYPE get(std::size_t hashid)
{
std::map<std::size_t, data_cache_t> &obj = get_pz_cache<data_cache_t>();
unsigned int nowtime = http::timeid();
std::unique_lock<std::mutex> lock(editlock);
auto iter = obj.find(hashid);
if (iter != obj.end())
{
if (iter->second.exptime == 0)
{
if (iter->second.data.size() > 0)
{
return iter->second.data[0];
}
}
if (iter->second.exptime >= nowtime)
{
if (iter->second.data.size() > 0)
{
return iter->second.data[0];
}
}
else
{
obj.erase(iter++);
}
}
lock.unlock();
BASE_TYPE temp;
return temp;
}
static pzcache &conn()
{
static pzcache instance;
return instance;
}
public:
std::mutex editlock;
};
auto [_, success] = obj.insert({hashid, temp});
这个map insert 方法如果存在会插入失败,于是我用API指定是更新过期时间或删除重新添加,这一步巧妙利用了map这个特性,需要c++17以上。
然后使用方式就是很简单了
pzcache<std::string> &temp_cache = pzcache<std::string>::conn();
我们缓存一个string 对象,首先取得单例。
pzcache<std::string> &temp_cache = pzcache<std::string>::conn();
std::string namestring = "testname"; std::size_t cache_hashid = std::hash<std::string>{}(namestring); if (temp_cache.check(cache_hashid) > -1) { client << " 已经存在,不需要再存 "; } else { std::string cache_data = "This cache content!"; temp_cache.save(cache_hashid, cache_data, 30); client << "缓存新的内容"; }
然后我们在其它线程使用
pzcache<std::string> &temp_cache = pzcache<std::string>::conn();
std::string namestring = "testname";
std::size_t cache_hashid = std::hash<std::string>{}(namestring);
std::string cache_data = temp_cache.get(cache_hashid);
是不是很简单,c++ 强大的模板能力,一个通用类库设计好了,而且简单好用
欢迎使用 国产 C++ web 框架 paozhu 1.2.0 发布
源代码里面更多的设计模式可以参考,框架LICENSE反正为MIT模式,大家商用也没有问题。
https://github.com/hggq/paozhu
我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
我想用ruby编写一个小的命令行实用程序并将其作为gem分发。我知道安装后,Guard、Sass和Thor等某些gem可以从命令行自行运行。为了让gem像二进制文件一样可用,我需要在我的gemspec中指定什么。 最佳答案 Gem::Specification.newdo|s|...s.executable='name_of_executable'...endhttp://docs.rubygems.org/read/chapter/20 关于ruby-在Ruby中编写命令行实用程序
我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此
我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r
刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr
我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数
我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("