boost.asio使用简介

文章目录

  • 前言
  • 一、计时器使用
    • 1. 创建计时器,阻塞等待
    • 2. 创建计时器,非阻塞等待
    • 3. 周期性计时器
    • 4.将3写入类封装
    • 5.多线程程序的同步完成事件处理函数
  • 二、Sockets简介
    • 1.同步TCP客户端
    • 2.同步TCP服务端
    • 3.异步TCP服务端
    • 4 同步UDP客户端
    • 5 同步UDP服务端
    • 6 异步UDP服务端
    • 7 异步TCP/UDP服务
  • 参考网址


前言

The Boost.Asio库是为使用C++进行系统编程的程序员设计的,在系统编程中,通常需要访问操作系统功能(如网络)。特别是Boost。Asio致力于实现以下目标:

  • 便携性。该库应支持一系列常用的操作系统,并在这些操作系统之间提供一致的行为。

  • 可扩展性。该库应促进可扩展到数千个并发连接的网络应用程序的开发。每个操作系统的库实现都应该使用最能实现这种可伸缩性的机制。

  • 效率该库应支持分散采集I/O等技术,并允许程序最大限度地减少数据复制。

  • 从已建立的API(如BSD套接字)中建模概念。BSD套接字API被广泛地实现和理解,并且在许多文献中都有涉及。其他编程语言通常使用类似的接口来连接API。在合理的范围内,Boost。Asio应该利用现有的做法。

  • 易于使用。图书馆应采用工具包而非框架方法,为新用户提供较低的进入门槛。也就是说,它应该尽量减少前期投资,及时学习一些基本规则和指导方针。之后,库用户应该只需要了解正在使用的特定函数。

  • 进一步抽象的基础。该库应允许开发提供更高抽象级别的其他库。例如,常用协议(如HTTP)的实现。

尽管Boost.Asio最初主要专注于网络,其异步I/O的概念已经扩展到包括其他操作系统资源,如串行端口、文件描述符等。

即: Boost.Asio是可实现异步IO的网络编程库,它封装了socket, bind, listen, epoll等操作


一、计时器使用

在Linux系统上,boost::asio::steady_timer 是通过timerfd_create 和 timerfd_settime 等系统调用函数实现的。这些函数允许应用程序创建和设置定时器,并且可以以稳定的时间间隔触发定时器事件。

#include <sys/timerfd.h>
int timerfd_create(int clockid, int flags);

1. 创建计时器,阻塞等待

// 只有一个线程

#include <boost/asio.hpp>
// 使用asio库必须建立至少一个io执行上下文对象,如io_context,thread_pool
// io执行上下文提供了对io功能的访问
boost::asio::io_contex io;
boost::asio::steady_timer t(io, boost::asio::chrono::second(5)); // 对象构造出来后计时器就已经执行了
/*若这里的执行时间较长,则wait不阻塞*/
t.wait();  // wait 至到计时器结束

2. 创建计时器,非阻塞等待

// 只有一个线程

void print(const boost::system::error_code& e)
{}
boost::asio::io_contex io;
boost::asio::steady_timer t(io, boost:;asio::chrono::seconds(5));
// 该函数接受一个可调用对象,函数签名:void(const boost::system::error_code&)
t.async_wait(&print)
io.run();  // 阻塞,至到所有工作都处理完

3. 周期性计时器

// 只有一个线程

#include <functional>
#include <boost/asio.hpp>
void print(const boost::system::error_code&, boost::asio::steady_timer*, t, int *count)
{if (*count < 5){++(*count);// expires_at设置到期时间点,expiry()返回到期的时间点// expiry返回一个time_pointt->expires_at(t->expiry() + boost::asio::chrono::seconds(1));// 异步等待,当到期时注册的函数会被调用t->async_wait(std::bind(print, boost::asio::placeholders::error, t, count));}
}boost::asio::io_context io;
int count = 0;
boost::asio::steady_timer t(io, boost::asio::chrono::seconds(1));
t.async_wait(std::bind(print, boost::asio::placeholders::error, &t, &count));
io.run()

std::bind为创建一个可调用对象,可更改该对象的函数签名

void fun(int a, int b, int c, int d) {}
auto bind_fun = std::bind(fun, a, b, std::placeholders::_1, d);
bind_fun(c);std::_Placeholder<9> s;auto b_fun = std::bind(fun, 1, s);  // fun后面为传入函数的参数b_fun(1,2,3,4,5,6,7,8,9); // 分别是placeholders::_1 _2 _3 ... _9

4.将3写入类封装

#include <functional>
#include <iostream>
#include <boost/asio.hpp>class printer
{
public:printer(boost::asio::io_context& io): timer_(io, boost::asio::chrono::seconds(1)),count_(0){timer_.async_wait(std::bind(&printer::print, this));  // 没有placeholders也是可以的}~printer(){std::cout << "Final count is " << count_ << std::endl;}void print(){if (count_ < 5){std::cout << count_ << std::endl;++count_;timer_.expires_at(timer_.expiry() + boost::asio::chrono::seconds(1));timer_.async_wait(std::bind(&printer::print, this));}}
private:boost::asio::steady_timer timer_;int count_;
};int main()
{boost::asio::io_context io;printer p(io);io.run();return 0;
}

5.多线程程序的同步完成事件处理函数

注册的函数会在调用run的线程中执行,如果有多个线程同时调用了run呢?

// 多线程
如果有两个线程同时调用 run() 函数,每个线程都将从 io_context 的事件队列中获取事件并执行它们。由于您的 printer 类在构造函数中设置了两个定时器 t1_ 和 t2_,并且它们都是异步等待的,因此在每个定时器到期时,将触发相应的处理函数 print1() 和 print2()。

当两个线程同时调用 run() 时,它们将竞争 io_context 的事件队列,但由于 io_context 本身是线程安全的,因此它们不会相互干扰或导致竞态条件。每个线程将按照事件在队列中的顺序处理它们。

总体来说,两个线程将会以并发的方式执行 io_context 中的事件,但由于事件的触发和处理是按照事件队列的顺序进行的,因此您的打印机类的 print1() 和 print2() 函数也将按照预期的顺序执行。

#include <functional>
#include <iostream>
#include <thread>
#include <boost/asio.hpp>using namespace std;
namespace asio = boost::asio;class printer
{
private:// 提供线程安全的序列化执行,以确保异步操作在多线程环境中的顺序性asio::strand<asio::io_context::executor_type> strand_;asio::steady_timer t1_;asio::steady_timer t2_;int count_;
public:printer(asio::io_context& io): strand_(asio::make_strand(io)),t1_(io, asio::chrono::seconds(1)),t2_(io, asio::chrono::seconds(1)),count_(0){// strand_ 执行器与 print1 方法绑定在一起,这样就确保了 print1 方法在 strand_ 执行器上执行t1_.async_wait(asio::bind_executor(strand_, bind(&printer::print1, this)));t2_.async_wait(asio::bind_executor(strand_, bind(&printer::print2, this)));}~printer(){cout << "final count is " << count_ << endl;}void print1(){if (count_ < 10){cout << "T1: " << count_ << " thid: " << this_thread::get_id() << endl;++count_;t1_.expires_at(t1_.expiry() + asio::chrono::milliseconds(100));t1_.async_wait(asio::bind_executor(strand_, bind(&printer::print1, this)));}else if (count_ < 1000){cout << "T1: " << count_ << " thid: " << this_thread::get_id() << endl;++count_;t1_.expires_at(t1_.expiry() + asio::chrono::milliseconds(200));t1_.async_wait(asio::bind_executor(strand_, bind(&printer::print1, this)));}}void print2(){if (count_ < 1000){cout << "T2: " << count_<< " thid: " << this_thread::get_id() << endl;++count_;t2_.expires_at(t2_.expiry() + asio::chrono::milliseconds(100));t2_.async_wait(asio::bind_executor(strand_, bind(&printer::print2, this)));}}
};int main()
{asio::io_context io;printer p(io);thread t([&]{io.run();});// 不调用run,注册函数就不会被执行io.run();t.join();return 0;
}

二、Sockets简介

Daytime Protocol:
服务端无论接受到什么都返回当前日期
Weekday, Month Day, Year Time-Zone
Tuesday, February 22, 1982 17:37:43-PST

1.同步TCP客户端

socket
connet

using boost::asio::ip::tcp;
namespace asio = boost::asio;
try
{// 使用asio库必须建立至少一个io执行上下文对象asio::io_context io_context;// 将xxx解析成xxxtcp::resolver resolver(io_context);tcp::resolver::results_type endpoints = resolver.resolve(argv[1], "daytime");// 创建socket,建立连接tcp::socket socket(io_context);boost::asio::connect(socket, endpoints);for (;;){std::array<char, 128> buf;boost::system::error_code error;// 阻塞读取数据size_t len = socket.read_some(boost::asio::buffer(buf), error);if (error == boost::asio::error::eof)break; // Connection closed cleanly by peer.else if (error)throw boost::system::system_error(error); // Some other error.std::cout.write(buf.data(), len);}
}
catch (std::exception& e)
{std::cerr << e.what() << std::endl;
}

2.同步TCP服务端

socket
bind
listen
accept

boost::asio::io_context io_context;tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), 13));for (;;)
{tcp::socket socket(io_context);acceptor.accept(socket);  // 阻塞,等待客户端连接std::string message = make_daytime_string();boost::system::error_code ignored_error;boost::asio::write(socket, boost::asio::buffer(message), ignored_error);
}

3.异步TCP服务端

std::enable_shared_from_this 是一个 C++11 标准库提供的模板类,位于 <memory> 头文件中。它的作用是允许一个对象可以在 tcp_connection 的成员函数中调用 shared_from_this() 方法来获取指向当前对象的 std::shared_ptr

// 函数原型
template<typename AsyncWriteStream, typename ConstBufferSequence, typename WriteHandler>
void async_write(AsyncWriteStream & s, const ConstBufferSequence & buffers, WriteHandler handler);io_context io;ip::tcp::socket socket(io);socket.connect(ip::tcp::endpoint(ip::address::from_string("127.0.0.1"), 8080));std::string data = "Hello, world!";async_write(socket, boost::asio::buffer(data),[](const boost::system::error_code& error, std::size_t bytes_transferred) {if (!error) {std::cout << "Data sent successfully." << std::endl;} else {std::cerr << "Error: " << error.message() << std::endl;}});io.run();
//using namespace boost::asio;  // asio is namespace, 将namespace 中的内容释放出来
//namespace asio = boost::asio; 
//using boost::asio::ip::tcp;   // tcp is class#include <ctime>
#include <functional>
#include <iostream>
#include <memory>
#include <string>
#include <boost/asio.hpp>
namespace asio = boost::asio;
using boost::asio::ip::tcp;
class tcp_connection : public std::enable_shared_from_this<tcp_connection > {private:tcp_connection(asio::io_context& io):socket_(io) {}void handle_write(const boost::system::error_code&, size_t){}tcp::socket socket_;std::string message_;public:typedef std::shared_ptr<tcp_connection> pointer;static pointer create(asio::io_context& io){ return pointer(new tcp_connection(io)); }tcp::socket& socket(){ return socket_; }void start(){// message_ = get_time();// 该函数保证整个数据块被发送message_ = "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\n";    asio::async_write(                                                     // 这里用shared_from_this而非socket_, asio::buffer(message_), std::bind(&tcp_connection::handle_write, shared_from_this(),asio::placeholders::error, asio::placeholders::bytes_transferred));}};
class tcp_server{private:asio::io_context& io_;tcp::acceptor acceptor_;void start_accept() {tcp_connection::pointer new_conn = tcp_connection::create(io_);acceptor_.async_accept(new_conn->socket(), std::bind(&tcp_server::handle_accept, this, new_conn, asio::placeholders::error));}void handle_accept(tcp_connection::pointer new_conn, const boost::system::error_code& error) {if (!error) {new_conn->start();}start_accept();}public:tcp_server(asio::io_context& io) :io_(io), acceptor_(io, tcp::endpoint(tcp::v4(), 9000)) {start_accept();}
};
int main()
{try{asio::io_context io;  // 使用asio必须有io上下文对象tcp_server server(io);io.run();} catch (std::exception& e) {std::cerr << e.what() << std::endl;}return 0;
}

只有一个线程
执行流解析:
tcp_server server(io);->start_accept()->async_accept(注册异步接收事件,当事件发生是调用handle_accept)-> io.run()在此处阻塞。
当有事件发生时:从io.run的阻塞处跳转至handle_accept执行->start->async_write(异步写数据)-> start_accept(再次注册) -> 跳回到 io.run()在此处阻塞

4 同步UDP客户端

#include <array>
#include <iostream>
#include <boost/asio.hpp>using namespace std;
using boost::asio::ip::udp;
namespace ip = boost::asio::ip;
namespace asio = boost::asio;int main(int argc, char* argv[])
{try{asio::io_context io;// 通过host,services获取远程endpoint// 获取远程信息,如远程地址,端口,udp::resolver resolver(io);udp::endpoint receiver_endpoint = // 解引用是安全的,至少返回一个*resolver.resolve(udp::v4(), argv[1], "daytime").begin(); ip::address::from_string("127.0.0.1");// udp::socket socket(io);socket.open(udp::v4());array<char, 1> send_buf{0};socket.send_to(asio::buffer(send_buf), udp::endpoint(ip::address::from_string(argv[1]), 9000));array<char, 128> recv_buf;udp::endpoint sender_endpoint;// 由receive_from初始化endpoint 获取服务器相关信息size_t len = socket.receive_from(asio::buffer(recv_buf), sender_endpoint);cout.write(recv_buf.data(), len);// cout << recv_buf.data() << endl;}catch(const std::exception& e){std::cerr << "WAHT?:" << e.what() << '\n';}
}

5 同步UDP服务端

#include <array>
#include <ctime>
#include <iostream>
#include <string>
#include <boost/asio.hpp>using boost::asio::ip::udp;std::string make_daytime_string()
{using namespace std; // For time_t, time and ctime;time_t now = time(0);return ctime(&now);
}int main()
{try{boost::asio::io_context io_context;udp::socket socket(io_context, udp::endpoint(udp::v4(), 9000));for (;;){std::array<char, 1> recv_buf;udp::endpoint remote_endpoint;socket.receive_from(boost::asio::buffer(recv_buf), remote_endpoint);std::string message = "HTTP/1.1 200 OK\r\nContent-Type:text\r\n\r\n";message += make_daytime_string();boost::system::error_code ignored_error;socket.send_to(boost::asio::buffer(message),remote_endpoint, 0, ignored_error);}}catch (std::exception& e){std::cerr << e.what() << std::endl;}return 0;
}

6 异步UDP服务端

#include <array>
#include <ctime>
#include <functional>
#include <iostream>
#include <memory>
#include <string>
#include <boost/asio.hpp>using boost::asio::ip::udp;std::string make_daytime_string()
{using namespace std; // For time_t, time and ctime;time_t now = time(0);return ctime(&now);
}class udp_server
{
public:udp_server(boost::asio::io_context& io_context): socket_(io_context, udp::endpoint(udp::v4(), 13)){start_receive();}private:void start_receive(){socket_.async_receive_from(boost::asio::buffer(recv_buffer_), remote_endpoint_,std::bind(&udp_server::handle_receive, this,boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred));}void handle_receive(const boost::system::error_code& error,std::size_t /*bytes_transferred*/){if (!error){std::shared_ptr<std::string> message(new std::string(make_daytime_string()));socket_.async_send_to(boost::asio::buffer(*message), remote_endpoint_,std::bind(&udp_server::handle_send, this, message,boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred));start_receive();}}void handle_send(std::shared_ptr<std::string> /*message*/,const boost::system::error_code& /*error*/,std::size_t /*bytes_transferred*/){}udp::socket socket_;udp::endpoint remote_endpoint_;std::array<char, 1> recv_buffer_;
};int main()
{try{boost::asio::io_context io_context;udp_server server(io_context);io_context.run();}catch (std::exception& e){std::cerr << e.what() << std::endl;}return 0;
}

7 异步TCP/UDP服务

#include <array>
#include <ctime>
#include <functional>
#include <iostream>
#include <memory>
#include <string>
#include <boost/asio.hpp>using boost::asio::ip::tcp;
using boost::asio::ip::udp;std::string make_daytime_string()
{using namespace std; // For time_t, time and ctime;time_t now = time(0);return ctime(&now);
}class tcp_connection: public std::enable_shared_from_this<tcp_connection>
{
public:typedef std::shared_ptr<tcp_connection> pointer;static pointer create(boost::asio::io_context& io_context){return pointer(new tcp_connection(io_context));}tcp::socket& socket(){return socket_;}void start(){message_ = make_daytime_string();boost::asio::async_write(socket_, boost::asio::buffer(message_),std::bind(&tcp_connection::handle_write, shared_from_this()));}private:tcp_connection(boost::asio::io_context& io_context): socket_(io_context){}void handle_write(){}tcp::socket socket_;std::string message_;
};class tcp_server
{
public:tcp_server(boost::asio::io_context& io_context): io_context_(io_context),acceptor_(io_context, tcp::endpoint(tcp::v4(), 13)){start_accept();}private:void start_accept(){tcp_connection::pointer new_connection =tcp_connection::create(io_context_);acceptor_.async_accept(new_connection->socket(),std::bind(&tcp_server::handle_accept, this, new_connection,boost::asio::placeholders::error));}void handle_accept(tcp_connection::pointer new_connection,const boost::system::error_code& error){if (!error){new_connection->start();}start_accept();}boost::asio::io_context& io_context_;tcp::acceptor acceptor_;
};class udp_server
{
public:udp_server(boost::asio::io_context& io_context): socket_(io_context, udp::endpoint(udp::v4(), 9000)){start_receive();}private:void start_receive(){socket_.async_receive_from(boost::asio::buffer(recv_buffer_), remote_endpoint_,std::bind(&udp_server::handle_receive, this,boost::asio::placeholders::error));}void handle_receive(const boost::system::error_code& error){if (!error){std::shared_ptr<std::string> message(new std::string(make_daytime_string()));socket_.async_send_to(boost::asio::buffer(*message), remote_endpoint_,std::bind(&udp_server::handle_send, this, message));start_receive();}}void handle_send(std::shared_ptr<std::string> /*message*/){}udp::socket socket_;udp::endpoint remote_endpoint_;std::array<char, 1> recv_buffer_;
};int main()
{try{boost::asio::io_context io_context;tcp_server server1(io_context);udp_server server2(io_context);io_context.run();}catch (std::exception& e){std::cerr << e.what() << std::endl;}return 0;
}

参考网址

https://www.boost.org/doc/libs/1_84_0/doc/html/boost_asio.html
https://www.boost.org/doc/libs/1_84_0/doc/html/boost_asio/tutorial.html

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

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

相关文章

Ps下载安装免费(专业图像处理软件Ps安装包下载2024【Windows版】)

Adobe全家桶下载方式 将持续更新~ 文章目录 Adobe全家桶下载方式Ps下载方式【点我获取下载链接】我们的网站一、Ps简介声明 Ps下载方式【点我获取下载链接】 迅雷网盘下载&#xff1a;迅雷网盘下载方式百度网盘下载&#xff1a;百度网盘下载方式夸克网盘下载&#xff1a;夸克…

flume系列之:为flume agent组增加新的节点,提高flume agent组消费能力

flume系列之:为flume agent组增加新的节点,提高flume agent组消费能力 一、拷贝服务的systemctl文件二、拷贝jmx导出程序三、拷贝jmx导出数据格式配置文件四、拷贝flume agent配置五、启动flume agent和jmx服务一、拷贝服务的systemctl文件 flume agent服务flume agent jmx服…

登录凭证------

为什么需要登录凭证&#xff1f; web开发中&#xff0c;我们使用的协议http是无状态协议&#xff0c;http每次请求都是一个单独的请求&#xff0c;和之前的请求没有关系&#xff0c;服务器就不知道上一步你做了什么操作&#xff0c;我们需要一个办法证明我没登录过 制作登录凭…

有源电桥电路

有源电桥电路 有源电桥由A3运放的正向输入端与负向输入端电压相等且为零可知&#xff1a;G点&#xff08;待测阻抗Zx与被测阻抗Rs的连接点&#xff09;电平一直为零&#xff0c;也就是平衡点虚地点&#xff0c;Ux与Us也就变成参照虚地点的绝对相量电压。并且根据运放的虚断原理…

FFmpeg——开源的开源的跨平台音视频处理框架简介

引言&#xff1a; FFmpeg是一个开源的跨平台音视频处理框架&#xff0c;可以处理多种音视频格式。它由Fabrice Bellard于2000年创建&#xff0c;最初是一个只包括解码器的项目。后来&#xff0c;很多开发者参与其中&#xff0c;为FFmpeg增加了多种新的功能&#xff0c;例如编码…

U盘秒变“零字节”?数据恢复全攻略!

一、遭遇U盘“零字节”危机 在数字化时代的浪潮中&#xff0c;U盘凭借其便携性和大容量&#xff0c;早已成为我们工作和生活中不可或缺的数据存储工具。然而&#xff0c;有时我们可能会突然遭遇一个令人头疼的问题——U盘显示0字节。明明前一天还存满了重要的文件&#xff0c;…

WPF自定义快捷命令

1、创建一个类 public class CustomCommandTest {private static RoutedUICommand customCommand;public static RoutedUICommand CustomCommand{get { return customCommand; }}static CustomCommandTest(){InputGestureCollection inputGestureCollection new InputGesture…

Android视角看鸿蒙第四课(module.json中的各字段含义之descriptionmainElement)修改程序入口

Android视角看鸿蒙第三课(module.json中的各字段含义之description&mainElement) 前言 上编文章了解了module.json中的name和type两个字段的含义及变更字段需要注意的事项&#xff0c;也明白了如何去实现类似Android library的功能。 这篇文章继续了解module.json中的des…

指针总结及例题总结

1 定义 指针是用来存放地址的变量 不同类型的指针变量所占用的存储空间是相同的&#xff0c;sizeof(int)sizeof(char)sizeof(double)... *是解引用操作符&#xff0c;&是取地址操作符&#xff0c;两者有着抵消作用 int a20;int* p&a;*p*&a20; 2&#xff0c;…

【C++11】包装器和bind

文章目录 一. 为什么要有包装器&#xff1f;二. 什么是包装器&#xff1f;三. 包装器的使用四. bind 函数模板1. 为什么要有 bind &#xff1f;2. 什么是 bind ?3. bind 的使用场景 一. 为什么要有包装器&#xff1f; function 包装器&#xff0c;也叫作适配器。C 中的 funct…

Vue.js计算属性:实现数据驱动的利器

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

RESTful API学习

RESTful API REST&#xff08;英文&#xff1a;Representational State Transfer&#xff0c;简称REST&#xff0c;直译过来表现层状态转换&#xff09;是一种软件架构风格、设计风格&#xff0c;而不是标准&#xff0c;只是提供了一组设计原则和约束条件。它主要用于客户端和…

光伏数字化管理平台:驱动绿色能源革命的智能化引擎

随着全球对可再生能源需求的不断增长&#xff0c;光伏产业已经成为推动绿色能源革命的重要力量。在这个背景下&#xff0c;光伏数字化管理平台应运而生&#xff0c;以其强大的数据处理、实时监控和智能优化功能&#xff0c;为光伏电站的运营管理和维护带来了革命性的变革。 光伏…

储能系统--户用储能美洲市场(三)

2、美洲市场 2.1、美国户储发展驱动力 &#xff08;1&#xff09;电网老化带来配储需求&#xff0c;户用光储成家庭第二用电保障 美国大部分电网建于20世纪60和70年代&#xff0c;超70%以上的输电系统已经超过了25年&#xff0c;在高负荷运转或者外部环境承压时&#xff0c;…

JSON查询(ccf 201709-3)解题思路

问题描述   JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式&#xff0c;可以用来描述半结构化的数据。JSON 格式中的基本单元是值 (value)&#xff0c;出于简化的目的本题只涉及 2 种类型的值&#xff1a;   * 字符串 (string)&#xff1a;字符串是由双引号…

深入理解Hive:探索不同的表类型及其应用场景

文章目录 1. 引言2. Hive表类型概览2.1 按照数据存储位置2.2 按照数据管理方式2.3 按照查询优化2.4 按照数据的临时性和持久性 3. 写在最后 1. 引言 在大数据时代&#xff0c;Hive作为一种数据仓库工具&#xff0c;为我们提供了强大的数据存储和查询能力。了解Hive的不同表类型…

【洛谷千题详解】P1613 跑路

目录 题目总览 题目描述 输入格式 输出格式 思路分析 AC代码 题目总览 题目描述 小 A 的工作不仅繁琐&#xff0c;更有苛刻的规定&#xff0c;要求小 A 每天早上在 6:00 之前到达公司&#xff0c;否则这个月工资清零。可是小 A 偏偏又有赖床的坏毛病。于是为了保住自己的…

【English Learnging】Day9

2024/03/010 和小录打卡的第9天 目录 Words & phrases Words & phrases possibility a job possiblity 工作机会creation the latest creation 最新的创作landing a safe landing 安全着陆pledge make a pledge 做出承诺expextancy an air of expectancy 期盼的心情au…

HTML世界之标签Ⅱ

目录 一、base 标签 二、bdi 标签 三、bdo 标签 四、blockquote 标签 五、br 标签 六、button 标签 七、canvas 标签 八、cite 标签 九、code 标签 十、colgroup 标签 十一、col 标签 十二、datalist 标签 十三、dd 标签 十四、del 标签 十五、details 标签…

【数学建模】层次分析

1.建立递阶层次结构模型 2.构造出各层次中的所有判断矩阵 对指标的重要性进行两两比较&#xff0c;构造判断矩阵&#xff0c;科学求出权重 矩阵中元素aij的意义是&#xff0c;第i个指标相对第j个指标的重要程度 对角线1&#xff0c;aijaji1 矛盾——>一致性检验