Linux 12:多线程2
1. 生产者消费者模型
生产者消费者模型有三种关系,两个角色,一个交易场所。
三种关系:
生产者之间是什么关系?竞争 - 互斥
消费者和消费者之间?竞争 - 互斥
消费者和消费者之间?互斥和同步
两个角色:
生产者和消费者
一个交易场所:
内存空间
1-1. 为何要使用生产者消费者模型
生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的。
1-2. 生产者消费者模型优点
- 解耦
- 支持并发
- 支持忙闲不均
2. 基于BlockingQueue的生产者消费者模型
BlockingQueue
在多线程编程中阻塞队列(Blocking Queue)是一种常用于实现生产者和消费者模型的数据结构。其与普通的队列区别在于,当队列为空时,从队列获取元素的操作将会被阻塞,直到队列中被放入了元素;当队列满时,往队列里存放元素的操作也会被阻塞,直到有元素被从队列中取出(以上的操作都是基于不同的线程来说的,线程在对阻塞队列进程操作时会被阻塞)。
2-1. C++ queue模拟阻塞队列的生产消费模型
为了便于理解,我们以单生产者,单消费者,来进行讲解,代码:
#include <iostream>
#include <queue>
#include <stdlib.h>
#include <pthread.h>
#define NUM 8
class BlockQueue
{
private:std::queue<int> q;int cap;pthread_mutex_t lock;pthread_cond_t full;pthread_cond_t empty;private:void LockQueue(){pthread_mutex_lock(&lock);}void UnLockQueue(){pthread_mutex_unlock(&lock);}void ProductWait(){pthread_cond_wait(&full, &lock);}void ConsumeWait(){pthread_cond_wait(&empty, &lock);}void NotifyProduct(){pthread_cond_signal(&full);}void NotifyConsume(){pthread_cond_signal(&empty);}bool IsEmpty(){return (q.size() == 0 ? true : false);}bool IsFull(){return (q.size() == cap ? true : false);}public:BlockQueue(int _cap = NUM) : cap(_cap){pthread_mutex_init(&lock, NULL);pthread_cond_init(&full, NULL);pthread_cond_init(&empty, NULL);}voidPushData(const int &data){LockQueue();while (IsFull()){NotifyConsume();std::cout << "queue full, notify consume data, product stop." << std::endl;ProductWait();}q.push(data);// NotifyConsume();UnLockQueue();}voidPopData(int &data){LockQueue();while (IsEmpty()){NotifyProduct();std::cout << "queue empty, notify product data, consume stop." << std::endl;ConsumeWait();}data = q.front();q.pop();// NotifyProduct();UnLockQueue();}~BlockQueue(){pthread_mutex_destroy(&lock);pthread_cond_destroy(&full);pthread_cond_destroy(&empty);}
};
void *consumer(void *arg)
{BlockQueue *bqp = (BlockQueue *)arg;int data;for (;;){bqp->PopData(data);std::cout << "Consume data done : " << data << std::endl;}
}
// more faster void *producter(void *arg)
{BlockQueue *bqp = (BlockQueue *)arg;srand((unsigned long)time(NULL));for (;;){int data = rand() % 1024;bqp->PushData(data);std::cout << "Prodoct data done: " << data << std::endl;// sleep(1);}
}
int main()
{BlockQueue bq;pthread_t c, p;pthread_create(&c, NULL, consumer, (void *)&bq);pthread_create(&p, NULL, producter, (void *)&bq);pthread_join(c, NULL);pthread_join(p, NULL);return 0;
}
3. POSIX信号量
POSIX信号量和SystemV信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源目的。 但POSIX可以用于线程间同步。
3-1. 初始化信号量
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
参数:
pshared:0表示线程间共享,非零表示进程间共享
value:信号量初始值
3-2. 销毁信号量
int sem_destroy(sem_t *sem);
3-3. 等待信号量
功能:等待信号量,会将信号量的值减1
int sem_wait(sem_t *sem); //P()
3-4. 发布信号量
功能:发布信号量,表示资源使用完毕,可以归还资源了。将信号量值加1。
int sem_post(sem_t *sem);//V()
上一节生产者-消费者的例子是基于queue的,其空间可以动态分配,现在基于固定大小的环形队列重写这个程序(POSIX信号量):
4. 基于环形队列的生产消费模型
- 环形队列采用数组模拟,用模运算来模拟环状特性
环形结构起始状态和结束状态都是一样的,不好判断为空或者为满,所以可以通过加计数器或者标记位来判断满或者空。另外也可以预留一个空的位置,作为满的状态。
但是我们现在有信号量这个计数器,就很简单的进行多线程间的同步过程。
#include <iostream>
#include <vector>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
#define NUM 16
class RingQueue
{
private:std::vector<int> q;int cap;sem_t data_sem;sem_t space_sem;int consume_step;int product_step;public:RingQueue(int _cap = NUM) : q(_cap), cap(_cap){sem_init(&data_sem, 0, 0);sem_init(&space_sem, 0, cap);consume_step = 0;product_step = 0;}void PutData(const int &data){sem_wait(&space_sem); // Pq[consume_step] = data;consume_step++;consume_step %= cap;sem_post(&data_sem); // V}void GetData(int &data){sem_wait(&data_sem);data = q[product_step];product_step++;product_step %= cap;sem_post(&space_sem);}~RingQueue(){sem_destroy(&data_sem);sem_destroy(&space_sem);}
};
void *consumer(void *arg)
{RingQueue *rqp = (RingQueue *)arg;int data;for (;;){rqp->GetData(data);std::cout << "Consume data done : " << data << std::endl;sleep(1);}
}
// more faster void *producter(void *arg)
{RingQueue *rqp = (RingQueue *)arg;srand((unsigned long)time(NULL));for (;;){int data = rand() % 1024;rqp->PutData(data);std::cout << "Prodoct data done: " << data << std::endl;// sleep(1);}
}
int main()
{RingQueue rq;pthread_t c, p;pthread_create(&c, NULL, consumer, (void *)&rq);pthread_create(&p, NULL, producter, (void *)&rq);pthread_join(c, NULL);pthread_join(p, NULL);
}
5. 线程池
一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。
线程池的应用场景:
- 需要大量的线程来完成任务,且完成任务的时间比较短。 WEB服务器完成网页请求这样的任务,使用线程池技术是非常合适的。因为单个任务小,而任务数量巨大,你可以想象一个热门网站的点击次数。 但对于长时间的任务,比如一个Telnet连接请求,线程池的优点就不明显了。因为Telnet会话时间比线程的创建时间大多了。
- 对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。
- 接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。突发性大量客户请求,在没有线程池情况下,将产生大量线程,虽然理论上大部分操作系统线程数目最大值不是问题,短时间内产生大量线程可能使内存到达极限,出现错误。
线程池示例:
- 创建固定数量线程池,循环从任务队列中获取任务对象,
- 获取到任务对象后,执行任务对象中的任务接口
threadpool.hpp
#pragma once
#include <iostream>
#include <queue>
#include <pthread.h>
#define MAX_THREAD 5
typedef bool (*handler_t)(int);
class ThreadTask
{
private:int _data;handler_t _handler;public:ThreadTask() : _data(-1), _handler(NULL) {}ThreadTask(int data, handler_t handler){_data = data;_handler = handler;}void SetTask(int data, handler_t handler){_data = data;_handler = handler;}void Run(){_handler(_data);}
};
class ThreadPool
{
private:int _thread_max;int _thread_cur;bool _tp_quit;std::queue<ThreadTask *> _task_queue;pthread_mutex_t _lock;pthread_cond_t _cond;private:void LockQueue(){pthread_mutex_lock(&_lock);}void UnLockQueue(){pthread_mutex_unlock(&_lock);}void WakeUpOne(){pthread_cond_signal(&_cond);}void WakeUpAll(){pthread_cond_broadcast(&_cond);}void ThreadQuit(){_thread_cur--;UnLockQueue();pthread_exit(NULL);}void ThreadWait(){if (_tp_quit){ThreadQuit();}pthread_cond_wait(&_cond, &_lock);}bool IsEmpty(){return _task_queue.empty();}static void * thr_start(void *arg){ThreadPool *tp = (ThreadPool *)arg;while (1){tp->LockQueue();while (tp->IsEmpty()){tp->ThreadWait();}T hreadTask *tt;tp->PopTask(&tt);tp->UnLockQueue();tt->Run();delete tt;}return NULL;}public:ThreadPool(int max = MAX_THREAD) : _thread_max(max), _thread_cur(max),_tp_quit(false){pthread_mutex_init(&_lock, NULL);pthread_cond_init(&_cond, NULL);}~ThreadPool(){pthread_mutex_destroy(&_lock);pthread_cond_destroy(&_cond);}bool PoolInit(){pthread_t tid;for (int i = 0; i < _thread_max; i++){int ret = pthread_create(&tid, NULL, thr_start, this);if (ret != 0){std::cout << "create pool thread error\n";return false;}}return true;}bool PushTask(ThreadTask *tt){LockQueue();if (_tp_quit){UnLockQueue();return false;}_task_queue.push(tt);WakeUpOne();UnLockQueue();return true;}bool PopTask(ThreadTask **tt){*tt = _task_queue.front();_task_queue.pop();return true;}bool PoolQuit(){LockQueue();_tp_quit = true;UnLockQueue();while (_thread_cur > 0){WakeUpAll();usleep(1000);}return true;}
};
main.cpp
#include "threadpool.hpp"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
bool handler(int data)
{srand(time(NULL));int n = rand() % 5;printf("Thread: %p Run Tast: %d--sleep %d sec\n", pthread_self(), data, n);sleep(n);return true;
}
int main()
{int i;ThreadPool pool;pool.PoolInit();for (i = 0; i < 10; i++){ThreadTask *tt = new ThreadTask(i, handler);pool.PushTask(tt);}pool.PoolQuit();return 0;
}
6. 线程安全的单例模式
什么是单例模式
单例模式是一种 "经典的,常用的,常考的" 设计模式。
什么是设计模式
IT行业这么火,涌入的人很多。俗话说林子大了啥鸟都有,大佬和菜鸡们两极分化的越来越严重。为了让菜鸡们不太拖大佬的后腿,于是大佬们针对一些经典的常见的场景,给定了一些对应的解决方案,这个就是设计模式。
6-1. 单例模式的特点
某些类, 只应该具有一个对象(实例),就称之为单例。
在很多服务器开发场景中,经常需要让服务器加载很多的数据 (上百G) 到内存中。此时往往要用一个单例的类来管理这些数据。
6-2. 饿汉实现方式和懒汉实现方式
吃完饭,立刻洗碗,这种就是饿汉方式。
吃完饭,先把碗放下,然后下一顿饭用到这个碗了再洗碗,就是懒汉方式。
- 懒汉方式最核心的思想是 "延时加载"。从而能够优化服务器的启动速度。
6-2-1. 饿汉方式实现单例模式
template <typename T>
class Singleton {
static T data;
public:
static T* GetInstance() {
return &data;
}
};
只要通过Singleton这个包装类来使用 T 对象,则一个进程中只有一个T对象的实例。
6-2-2. 懒汉方式实现单例模式
template <typename T>
class Singleton {
static T* inst;
public:
static T* GetInstance() {
if (inst == NULL) {
inst = new T();
}
return inst;
}
};
- 存在一个严重的问题,线程不安全。
- 第一次调用GetInstance的时候,如果两个线程同时调用,可能会创建出两份T对象的实例。
- 但是后续再次调用,就没有问题了。
6-2-3. 懒汉方式实现单例模式(线程安全版本)
template <typename T>
class Singleton {
volatile static T* inst; // 需要设置 volatile 关键字, 否则可能被编译器优化.
static std::mutex lock;
public:
static T* GetInstance() {
if (inst == NULL) { // 双重判定空指针, 降低锁冲突的概率, 提高性能.
lock.lock(); // 使用互斥锁, 保证多线程情况下也只调用一次 new.
if (inst == NULL) {
inst = new T();
}
lock.unlock();
}
return inst;
}
};
注意事项:
- 锁解锁的位置。
- 双重if判定,避免不必要的锁竞争。
- volatile关键字防止过度优化。
7. STL,智能指针和线程安全
7-1.STL中的容器是否是线程安全的?
不是。
原因是,STL 的设计初衷是将性能挖掘到极致,而一旦涉及到加锁保证线程安全,会对性能造成巨大的影响。
而且对于不同的容器,加锁方式的不同,性能可能也不同(例如hash表的锁表和锁桶)。
因此STL默认不是线程安全。如果需要在多线程环境下使用,往往需要调用者自行保证线程安全。
7-2. 智能指针是否是线程安全的?
对于unique_ptr,由于只是在当前代码块范围内生效,因此不涉及线程安全问题。
对于shared_ptr,多个对象需要共用一个引用计数变量,所以会存在线程安全问题。但是标准库实现的时候考虑到了这个问题,基于原子操作(CAS)的方式保证shared_ptr能够高效,原子的操作引用计数。
8. 其他常见的各种锁
- 悲观锁:在每次取数据时,总是担心数据会被其他线程修改,所以会在取数据前先加锁(读锁,写锁,行锁等),当其他线程想要访问数据时,被阻塞挂起。
- 乐观锁:每次取数据时候,总是乐观的认为数据不会被其他线程修改,因此不上锁。但是在更新数据前,会判断其他数据在更新前有没有对数据进行修改。主要采用两种方式:版本号机制和CAS操作。
- CAS操作:当需要更新数据时,判断当前内存值和之前取得的值是否相等。如果相等则用新值更新。若不等则失败,失败则重试,一般是一个自旋的过程,即不断重试。
- 自旋锁,公平锁,非公平锁。
相关文章:
Linux 12:多线程2
1. 生产者消费者模型 生产者消费者模型有三种关系,两个角色,一个交易场所。 三种关系: 生产者之间是什么关系?竞争 - 互斥 消费者和消费者之间?竞争 - 互斥 消费者和消费者之间?互斥和同步 两个角色: 生产者和消费者 一个交…...
Android RSA 加解密
文章目录 一、RSA简介二、RSA 原理介绍三、RSA 秘钥对生成1. 密钥对生成2. 获取公钥3. 获取私钥 四、PublicKey 和PrivateKey 的保存1. 获取公钥十六进制字符串1. 获取私钥十六进制字符串 五、PublicKey 和 PrivateKey 加载1. 加载公钥2. 加载私钥 六、 RSA加解密1. RSA 支持三…...
类与对象-多态-案例3-电脑组装具体实现
#include<iostream> #include<string> using namespace std; //CPU class CPU { public:virtual void calculate() 0; }; //显卡 class GraCard { public:virtual void graphics() 0; }; //存储 class Memory { public:virtual void memory() 0; }; class Compu…...
try-with-resources 语句的用途和优点有哪些,它如何自动管理资源?
在Java编程中,资源管理是一个重要的议题,尤其是当你在代码中使用那些需要显式关闭的资源,比如文件流、数据库连接或者网络套接字等。 如果资源使用完毕后忘记关闭,不仅会导致资源泄露,还可能引起程序性能问题甚至系统…...
GraphRAG参数与使用步骤 | 基于GPT-4o-mini实现更便宜的知识图谱RAG
首先给兄弟朋友们展示一下结论,一个文本18万多字,txt文本大小185K,采用GraphRAG,GPT-4o-mini模型,索引耗时差不多5分钟,消耗API价格0.15美元 GraphRAG介绍 GraphRAG是微软最近开源的一款基于知识图谱技术的框架&#…...
/秋招突击——7/21——复习{堆——数组中的第K大元素}——新作{回溯——全排列、子集、电话号码的字母组合、组合总和、括号生成}
文章目录 引言复习数组中的第K大的最大元素复习实现参考实现 新作回溯模板46 全排列个人实现参考实现 子集个人实现参考实现 电话号码的字母组合复习实现 组合总和个人实现参考实现 括号生成复习实现 总结 引言 昨天的科大讯飞笔试做的稀烂,今天回来好好练习一下&a…...
matlab 异常值检测与处理——Robust Z-score法
目录 一、算法原理1、概述2、主要函数3、参考文献二、代码实现三、结果展示四、相关链接本文由CSDN点云侠翻译,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、算法原理 1、概述 Robust Z-score法也被称为中位数绝对偏差法。它类似于Z-sc…...
Ubuntu 20安装JDK17和MySQL8.0
一.jdk 安装JDK 第一步:更新软件包:sudo apt update 第二步:安装JDK:sudo apt install openjdk-17-jdk 第三步:检测JDK: java -version 卸载JDK: 第一步:移除JDK包:apt-get purg…...
DC-1靶场打靶第一次!!!!冲冲冲!
今天打了一下DC-1这个靶场,感觉收获比大,我就来记录一下。 我的思路是下面的这个 我们先把靶机导入,然后与我们的liunx(攻击机)在同一个网段中,这也大大的减低难度。 然后我们先对自己这个网段内存活的主机进行操作,我…...
【LeetCode】填充每个节点的下一个右侧节点指针 II
目录 一、题目二、解法完整代码 一、题目 给定一个二叉树: struct Node { int val; Node *left; Node *right; Node *next; } 填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NUL…...
mac无法清空废纸篓怎么办 mac废纸篓清空了如何找回 cleanmymac误删文件怎么恢复
废纸篓相当于“一颗后悔药”,用于临时存储用户删除的文件。我们从从Mac上删除的文件,一般会进入废纸篓中。如果我们后悔了,可以从废纸篓中找回来。然而,有时我们会发现mac无法清空废纸篓,这是怎么回事?本文将探讨一些…...
树上启发加点分治思想
题目链接 思路: 对于一条链可以组成回文串,意味着最多只有一个奇数字母,比起我们记录路径各个字母的个数和,我们可以发现回文串实际上不在意真正的个数,只在意个数的奇偶。又我们发现字母只有20来个,可以使…...
【iOS】类对象的结构分析
目录 对象的分类object_getClass和class方法isa流程和继承链分析isa流程实例验证类的继承链实例验证 类的结构cache_t结构bits分析实例验证属性properties方法methods协议protocolsro类方法 类结构流程图解 对象的分类 OC中的对象主要可以分为3种:实例对象…...
接口性能优化思路
前言 日常开发中设计接口,响应时间是衡量一个接口质量的重要指标。 接口响应时间这里粗糙地分为三种: 即时响应:毫秒级,小于500毫秒快速响应:秒级,大于500毫秒且小于2秒长时间操作:大于2秒&a…...
PyQt5 多线程编程详细教程
PyQt5 多线程编程详细教程 在 PyQt5 中,多线程编程是提高应用程序性能和响应性的重要手段。本教程将详细介绍如何在 PyQt5 中使用 QThread 进行多线程编程,学习如何避免界面冻结和线程安全问题,并通过丰富的案例来展示如何实现这些功能。 Q…...
uniapp小程序上传pdf文件
<template><view class"mainInnBox"><view class"formBox"><!-- 注意,如果需要兼容微信小程序,最好通过setRules方法设置rules规则 --><u-form :model"form" ref"uForm" :rules&quo…...
Python酷库之旅-第三方库Pandas(036)
目录 一、用法精讲 111、pandas.Series.item方法 111-1、语法 111-2、参数 111-3、功能 111-4、返回值 111-5、说明 111-6、用法 111-6-1、数据准备 111-6-2、代码示例 111-6-3、结果输出 112、pandas.Series.xs方法 112-1、语法 112-2、参数 112-3、功能 112-…...
Python爬虫(2) --爬取网页页面
文章目录 爬虫URL发送请求UA伪装requests 获取想要的数据打开网页 总结完整代码 爬虫 Python 爬虫是一种自动化工具,用于从互联网上抓取网页数据并提取有用的信息。Python 因其简洁的语法和丰富的库支持(如 requests、BeautifulSoup、Scrapy 等…...
【iOS】——探究isKindOfClass和isMemberOfClass底层实现
isKindOfClass 判断该对象是否为传入的类或其子类的实例 // 类方法实现,用于检查一个类是否属于另一个类或其父类链上的任何类。(BOOL)isKindOfClass:(Class)cls {// 从当前类开始,tcls将沿着元类的继承链向上遍历。for (Class tcls self->ISA(); …...
Python 热门面试题(七)
Python中如何拷贝对象?浅拷贝和深拷贝的区别是什么? 在Python中,拷贝对象是一个常见的需求,尤其是当你需要修改一个对象但又不想影响原始对象时。Python提供了几种拷贝对象的方法,其中最重要的是浅拷贝(sh…...
STM32项目分享:智能宠物喂食系统
目录 一、前言 二、项目简介 1.功能详解 2.主要器件 三、原理图设计 四、PCB硬件设计 1.PCB图 五、程序设计 六、实验效果 七、资料内容 项目分享 一、前言 项目成品图片: 哔哩哔哩视频链接: https://www.bilibili.com/video/BV1zy411z7…...
数据结构——栈的实现(java实现)与相应的oj题
文章目录 一 栈栈的概念:栈的实现:栈的数组实现默认构造方法压栈获取栈元素的个数出栈获取栈顶元素判断当前栈是否为空 java提供的Stack类Stack实现的接口: LinkedList也可以当Stack使用虚拟机栈,栈帧,栈的三个概念 二 栈的一些算…...
linux修改时区为CST
目录 第一步: 第二步: 第三步: 第一步: 备份原来的时区信息 [rootlocalhost ~]# mv /etc/localtime localtime.bak 第二步: 通过软链接将亚洲/上海 的时区信息 指导时区信息 [rootlocalhost ~]# ln -s /usr/share…...
【Spring Security】初识Spring Security
今天晚上因为一个项目问题,而正式开始学习Spring Security。 这个问题是“APP端的操作员应仅可查看管理后台的项目负责人分配给自己的计划”。 一、Spring Security的核心组件: Spring Security的核心组件包括:SecurityContextHolder、Auth…...
配置单区域OSPF
目录 引言 一、搭建基础网络 1.1 配置网络拓扑图如下 1.2 IP地址表 二、测试每个网段都能单独连通 2.1 PC0 ping通Router1所有接口 2.2 PC1 ping通Router1所有接口 2.3 PC2 ping通Router2所有接口 2.4 PC3 ping通Router2所有接口 2.5 PC4 ping通Router3所有接口 2.…...
SQL中的游标是什么?
在 SQL 中,游标(Cursor)是一种用于遍历结果集的数据库对象。它允许开发者在 SQL 查询的结果集中逐行或逐批处理数据。 具体来说,SQL 中的游标通常用于以下目的: 遍历结果集:当一个 SQL 查询返回多行结果时…...
7. LangChain4j如何使用统一api调用?
前言 当我们对接LangChain4j的时候,面对复杂的各种各样的大模型的api的对接,让很多开发者感到力不从心。在每个大模型的api都不一样的时候?该如何快捷的切换模型的使用呢? 这时,One-API应运而生,它以其简洁…...
RPM、YUM 安装 xtrabackup 8 (mysql 热备系列一)包含rpm安装 mysql 8 配置主从
RPM安装 percona-xtrabackup-80-8.0.35-30.1.el7.x86_64.rpm 官网: https://www.percona.com/ 下载地址: https://www.percona.com/downloads wget https://downloads.percona.com/downloads/percona-distribution-mysql-ps/percona-distribution-mysq…...
maven项目打成可运行的jar及pom中的依赖一同打包
maven项目打jar及pom中的依赖一同打包 最近开发中有个需求,不部署新的服务,只jar包执行 那maven项目中,代码如何以jar的方式运行、如何把代码打成jar、pom中的依赖如何与代码一同打到jar包中? 1、代码如何以jar的方式运行&…...
Gettler‘s Screep World 笔记 Ⅰ
夏促时候刚刚入坑,写个笔记叭~ 环境配置 参考 HoPGoldy 大佬的简书,先配置下开发环境 萌新去看大佬的详细教程,我这里比较简单,有前端基础的可以直接抄 VSCode 跳过 node 我配的是v18.18.2 换源 npm config set registry h…...
雅虎网站收录提交入口/千锋教育的口碑怎么样
为什么80%的码农都做不了架构师?>>> 微服务需要考虑的几点内容, :) 团队规模 团队成员能否围坐在一张桌边? Yes! -- 你可能不需要微服务 好文档和好设计可以轻易解决部署等运维操作中遇到的挑战。而微服务要解决的问题你还没有遇…...
韶关企业网站建设公司/精准营销名词解释
回到目录 一些概念 在大叔框架里总觉得缺点什么,在最近的项目开发中,终于知道缺什么了,分布式文件存储组件,就是缺它,呵呵,对于分布式文件存储来说,业界比较公认的是FastDFS组件,它自…...
江苏省省建设集团网站/品牌策划与推广方案
假设我们有三个表,A表,B表,C表.其数据量分别为100,200,300条记录.并且假设每次都是完全遍历所有数据才找到结果(其实一般情况下不会真的需要完全遍历完才能找到结果),并且假设不考虑索引,当然,就算不排除这些因素,结果比例还是一样的,只是数据大小上有点不一样.并且假设每次查询…...
网站建设的意义怎么写/百度小程序优化
对于前后端分离,如何把一个页面的公共部分比如head, header, footer, content等组合成一个完整的html 是一个值得考虑的地方。 对于php,我们可以利用include加载其他页面,像yii框架,可以利用render将输出的内容嵌入到父模板&#…...
网站建设经营范围/公众号排名优化软件
PropertyDescriptor类: PropertyDescriptor类表示JavaBean类通过存储器导出一个属性。主要方法: 1. getReadMethod(),获得用于读取属性值的方法 2. getWriteMethod(),获得用于写入属性值的方法 注:…...
丽水市龙泉市网站建设公司/搜索引擎营销怎么做
前端web开发工程师简历-自我评价范文/怎么写【网盘下载】100清新大气简历模板:https://zhuanlan.zhihu.com/p/115911695https://zhuanlan.zhihu.com/p/113308665前端工程师自我评价范文(案例1)1. 熟悉项目开发流程,能快速对接产品需求,前后端…...