Linux单列模式实现线程池
目录
一、单列模式
1.1 单列模式概念以及实现条件
1.2 饿汉模式
1.1.1 饿汉模式代码实现
1.1.2 饿汉模式特征和优缺点
1.3 懒汉模式
1.3.1 懒汉模式代码实现
1.3.2 懒汉模式特征以及优缺点
二、线程池
2.1 线程池概念
2.2 实现简单线程池逻辑
2.3 模拟实现懒汉模式线程池
2.3.1 mutex.hpp 封装锁
2.3.2 Task.hpp 任务封装
💡💡2.3.3 Thread.hpp 线程封装
2.3.4 ThreadPool.hpp 线程池封装
2.3.5 main.cc 上层代码
2.3.6 执行结果展示
2.4 线程池应用场景
一、单列模式
1.1 单列模式概念以及实现条件
单例模式主要确保一个类只有一个实例!也就是对象唯一。其中饿汉、懒汉模式是单列模式的一种。
使对象唯一的条件:
- 私有的构造函数:单例类应当拥有一个私有的构造函数,以防止外部代码创建该类的实例。
- 公有的静态方法:单例类应当提供一个公有的静态方法,以供外部代码获取该类的唯一实例。
- 私有的静态变量:单例类应当拥有一个私有的静态变量,用于存储该类的唯一实例。
- 线程安全:在多线程环境下,应当保证单例类的唯一实例的创建和获取都是线程安全的。
1.2 饿汉模式
1.1.1 饿汉模式代码实现
class Singleton {
public: //静态成员函数--》不需要this指针static Singleton& getInstance() { static Singleton instance; //静态成员对象--》生命周期长return instance; } // 防止拷贝构造函数和赋值运算符 Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; private: Singleton() {} //构造函数私有化
};
1.1.2 饿汉模式特征和优缺点
特征:
- 在类加载时就创建唯一实例,保证了一个类只有一个实例。
- 实现起来比较简单,没有多线程同步问题。
优点:
- 由于实例在类加载时就被创建,因此不会造成资源的浪费。
- 没有多线程同步问题,保证了线程安全。
缺点:
- 如果该类从未被使用,那么它的实例对象就会被创建并一直占用内存,即使该实例对象可能永远不会被使用。
1.3 懒汉模式
1.3.1 懒汉模式代码实现
#include <mutex> //懒汉模式 main函数之后创建对象
class InfoSingleton
{
public:static InfoSingleton& GetInstance(){//双重检查 最外面if可以保证不会每次都加锁判断if (_psins == nullptr){LockGuard<mutex> lock(_smtx);if (_psins == nullptr){_psins = new InfoSingleton;}}return *_psins;}private:InfoSingleton() {}//封死拷贝赋值构造InfoSingleton(const InfoSingleton& s) = delete;InfoSingleton& operator=(const InfoSingleton& s) = delete;static InfoSingleton* _psins;static mutex _smtx;
};
InfoSingleton* InfoSingleton::_psins = nullptr;
mutex InfoSingleton::_smtx;
1.3.2 懒汉模式特征以及优缺点
特征:
懒汉模式是一种单例模式,它的特点是在第一次使用实例对象时,才创建对象。
优点:
- 在第一次使用实例对象时,创建对象进程启动无负载。也就是说,如果单例对象构造十分耗时或者占用很多资源,如加载插件、初始化网络连接、读取文件等等,而有可能该对象在程序运行时并不会被使用,那么在程序一开始就进行初始化会导致程序启动时非常缓慢,使用懒汉模式(延迟加载)则能避免这种情况。
缺点:
- 懒汉模式相对于饿汉模式来说,实现上更复杂一些,因为涉及到线程安全问题。
二、线程池
2.1 线程池概念
线程池是一种多线程处理形式,它预先将任务添加到队列中,然后在创建线程后自动启动这些任务。线程池中的线程都是后台线程,每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。
2.2 实现简单线程池逻辑
线程池的工作原理如下:
- 线程池的初始化:在创建线程池后,线程池会根据配置初始化一定数量的核心线程,等待任务来临。--》单列模式实现线程池,提高创建线程的效率,有任务来立刻有执行线程!
- 线程的管理:线程池会管理线程的生命周期。当一个线程完成任务后,它会回到线程池中等待下一个任务--》利用一个数组来组织管理线程
- 任务的提交:线程池提供了接口供外部提交任务,这些任务会被封装为一个个的工作单元并加入到线程池的工作队列中。--》任务队列 Push接口放任务到队列,同步信号给线程
- 任务的执行:线程池中的线程会循环从工作队列中取出任务并执行。--》线程池Run->一个个线程Run互斥取任务
- 线程池的关闭:当不再需要线程池时,可以通过调用关闭方法来停止线程池。这将会停止所有正在执行的任务,销毁所有的核心线程,并释放线程池相关的资源。
2.3 模拟实现懒汉模式线程池
2.3.1 mutex.hpp 封装锁
RAII的思想,通过类生命周期来加锁解锁!
#include<iostream>
#include<pthread.h>class Mutex
{
public:Mutex(pthread_mutex_t* lock_p = nullptr):lock_p_(lock_p){}void lock(){if(lock_p_)pthread_mutex_lock(lock_p_);}void unlock(){if(lock_p_)pthread_mutex_unlock(lock_p_);}
private:pthread_mutex_t* lock_p_;
};class LockGuard
{
public:LockGuard(pthread_mutex_t* mutex):mutex_(mutex){mutex_.lock();}~LockGuard(){mutex_.unlock();}
private:Mutex mutex_;
};
2.3.2 Task.hpp 任务封装
#pragma once
#include<functional>
#include<iostream>
#include<unistd.h>
#include<string>
// 任务对象
class Task
{
public://==typedefusing func_t = std::function<double(int, int, char)>; Task() {}Task(func_t callback, int x = 0, int y = 0, char op = '+') : _x(x), _y(y), _op(op), _callback(callback){}// 仿函数std::string operator()(){double ret = _callback(_x, _y, _op);char buffer[64];snprintf(buffer, sizeof buffer, "%d %c %d = %lf", _x, _op, _y, ret);return buffer;}private:int _x;int _y;char _op;func_t _callback; // 回调函数
};//处理数据函数
double calculator(int x, int y, char op)
{double ret = 0.0;switch (op){case '+':ret = x + y;break;case '-':ret = x - y;break;case '*':ret = x * y;break;case '/':if (y == 0)ret = 0;elseret = (double)x / y;break;case '%':if (y == 0)ret = 0;elseret = x % y;break;default:break;}return ret;
}
💡💡2.3.3 Thread.hpp 线程封装
#pragma once
#include <iostream>
#include <string>
#include <pthread.h>
#include <functional>
#include <assert.h>
using func_t = std::function<void *(void *)>;
namespace MyThread
{class Thread{public:Thread(func_t callback, void *args = nullptr) : _callback(callback), _args(args){char namebuffer[64];snprintf(namebuffer, sizeof namebuffer, "thread %d ", ++threadNum);_name = namebuffer;}void start(){int n = pthread_create(&_tid, nullptr, start_route, (void *)this);assert(n == 0);(void)n;}void join(){pthread_join(_tid, nullptr);}std::string ThreadName(){return _name;}void *callback(){return _callback(_args);}private://在类中调用线程执行流函数必须要static-->因为默认的函数是只有一个void*参数,如果没有static,会默认带有隐藏参数this!//仅仅使用stati后,还要考虑如何访问类成员变量\函数-->传入的void*参数是this!static void *start_route(void *args){Thread *pt = static_cast<Thread *>(args);return pt->callback();}private: pthread_t _tid; //线程IDvoid *_args; //线程所拥有的资源std::string _name; //线程名称func_t _callback; //回调函数static int threadNum;//线程对象个数};int Thread::threadNum = 0;
}
2.3.4 ThreadPool.hpp 线程池封装
#pragma once
#include "Thread.hpp"
#include "mutex.hpp"
#include "Task.hpp"
#include <vector>
#include <queue>
#include <unistd.h>
#include <mutex>
using namespace MyThread;
static const int gnum = 5;template <class T>
class ThreadPool
{//和Thread.hpp中的理由一样 static防this指针 args=thisstatic void *Handeler(void *args){while (true){T t;ThreadPool<T> *Self = static_cast<ThreadPool<T> *>(args);{LockGuard lock(&Self->_mutex);while (Self->_TaskQueue.empty()){pthread_cond_wait(&Self->_cond, &Self->_mutex);}t = Self->_TaskQueue.front();Self->_TaskQueue.pop();}std::cout << "线程[" << pthread_self() << "]处理完了一个任务: " << t() << std::endl;}return nullptr;}//构造函数私有 初始化创建一批线程ThreadPool(const int num = gnum) : _num(num){pthread_mutex_init(&_mutex, nullptr);pthread_cond_init(&_cond, nullptr);for (int i = 0; i < _num; i++){_threads.push_back(new Thread(Handeler, this));}}//拷贝赋值封死ThreadPool(const ThreadPool<T> &) = delete;void operator=(const ThreadPool<T> &) = delete;public:// 懒汉模式 延迟加载static ThreadPool<T> *GetInstance(){if (_tp == nullptr){_singleton_lock.lock();if (_tp == nullptr)_tp = new ThreadPool<T>();_singleton_lock.unlock();}return _tp;}//执行线程void run(){for (const auto &t : _threads){t->start();std::cout << t->ThreadName() << "starts..." << std::endl;}}//放数据接口void push(const T &in){LockGuard lock(&_mutex);_TaskQueue.push(in);pthread_cond_signal(&_cond);}~ThreadPool(){pthread_mutex_destroy(&_mutex);pthread_cond_destroy(&_cond);for (const auto &t : _threads)delete t;}private:std::vector<Thread *> _threads; //数组管理线程int _num;std::queue<T> _TaskQueue; //任务队列pthread_mutex_t _mutex;//互斥pthread_cond_t _cond;// 同步//单列模式static ThreadPool<T> *_tp;static std::mutex _singleton_lock;
};
template <class T>
ThreadPool<T> *ThreadPool<T>::_tp = nullptr;
template <class T>
std::mutex ThreadPool<T>::_singleton_lock;
2.3.5 main.cc 上层代码
#include "ThreadPool.hpp"
#include <memory>
#include <unistd.h>int main()
{srand((unsigned long)time(nullptr) ^ getpid());//初始化并运行线程ThreadPool<Task>::GetInstance()->run();sleep(2);while (true){//1.获取任务const char *str = "+-*/%";int x = rand() % 10 + 1;int y = rand() % 5 + 1;char op = str[rand() % 5];Task t(calculator, x, y, op);//2.放入任务至队列中ThreadPool<Task>::GetInstance()->push(t);std::cout << "生产任务: " << x << " " << op << " " << y << " = ?" << std::endl;sleep(1);}while (true){sleep(1);}return 0;
}
2.3.6 执行结果展示
2.4 线程池应用场景
线程池主要应用在以下场景中:
- 处理CPU密集型任务:线程池可以预先创建一定数量的线程,避免在线程需要时创建线程,从而提高效率。这对于处理CPU密集型任务非常有用,例如进行大量计算或者处理某个特定任务。
- 面向用户的功能聚合:当业务开发中涉及到大量的并发调用时,线程池可以通过封装调用为任务并行执行的方式,提高整体响应时间。例如,如果一个系统有很多用户请求,线程池可以管理这些请求的并发执行,避免请求的阻塞。
此外,线程池在以下情况中也可以发挥出其优势:
- 任务执行时间短且数量大:如果需要执行大量的小任务,每个任务的处理时间都很短,此时使用线程池可以更有效地利用资源。
- 任务的执行顺序无关紧要:如果任务之间的执行顺序并不重要,那么线程池可以让任务异步执行,提高整体效率。
- 需要执行重复任务:如果需要执行重复的任务,使用线程池可以避免重复创建和销毁线程,提高性能和效率。
- 任务的间歇性执行:如果任务是间歇性地执行,使用线程池可以在需要时立即提供服务,避免空闲时间过长。
- 任务的响应时间要求高:如果要求任务的响应时间非常短,使用线程池可以更快地处理任务,提高用户体验。
- 需要限制并发数:如果需要限制并发执行的线程数量,线程池可以通过控制最大并发数来管理资源的使用。
总的来说,线程池主要应用在需要对并发执行的任务进行高效、有序、可控制管理的场景中。
相关文章:
Linux单列模式实现线程池
目录 一、单列模式 1.1 单列模式概念以及实现条件 1.2 饿汉模式 1.1.1 饿汉模式代码实现 1.1.2 饿汉模式特征和优缺点 1.3 懒汉模式 1.3.1 懒汉模式代码实现 1.3.2 懒汉模式特征以及优缺点 二、线程池 2.1 线程池概念 2.2 实现简单线程池逻辑 2.3 模拟实现懒汉模式线程…...
汇川PLC学习Day3:轴控代码编写、用户程序结构说明与任务配置示例、用户变量空间与编址
汇川PLC学习Day3:轴控代码编写、用户程序结构说明与任务配置示例、用户变量空间与编址 一、新建轴与轴控代码编写 1. 新建轴 (1)新建一个轴 (2)将轴名字更新为实际名字 可以后面实例化后再更改,汇川可以在更新名字时同步更新…...
javaee springMVC Map ModelMap ModelAndView el和jstl的使用
pom依赖 <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 …...
vue监听表单输入的身份证号自动填充性别和生日
1,先给表单绑定一个v-model值 <el-input type"number" v-model"form.idCard" placeholder"请输入证件号码" /> 2,使用watch监听输入的值 watch(form, (newName, oldName) > {var numid newName.idCard.split(…...
蓝桥杯官网练习题(翻硬币)
题目描述 小明正在玩一个"翻硬币"的游戏。 桌上放着排成一排的若干硬币。我们用 * 表示正面,用 o 表示反面(是小写字母,不是零)。 比如,可能情形是:**oo***oooo; 如果同时翻转左边的两个硬币…...
企业架构LNMP学习笔记34
LVS-DR模式: 老师分析: 1、首先用户用CIP请求VIP 2、根据上图可以看到,不管是Director Server还是Real Server上都需要配置VIP,那么当用户请求到达我们的集群网络的前端路由器的时候,请求数据包的源地址为CIP目标地址…...
Python学习之六 循环结构
在很多情况下,我们往往需要循环输入多次,比如,密码最多只能输错3次等。这时候,我们需要使用循环结构。本小节,将学习循环。 一、while循环 while循环的一般形式如下: while 判断条件: 循环语句块 当判断条件为真,便执行循环语句块。比如说,我们需要写一个判断账号…...
flutter 网络地址URL转file
方法1 import dart:io; import package:http/http.dart as http; import package:path/path.dart; import package:path_provider/path_provider.dart;Future<File> _fileFromImageUrl() async {final response await http.get(Uri.parse(https://example.com/xyz.jpg)…...
【JavaEE基础学习打卡07】JDBC之应用分层设计浅尝!
目录 前言一、简单说说应用分层二、实体层1.O/R映射2.O/R映射实践三、数据访问层1.DAO层2.DAO层实战总结前言 📜 本系列教程适用于JavaWeb初学者、爱好者,小白白。我们的天赋并不高,可贵在努力,坚持不放弃。坚信量最终引发质变,厚积薄发。 🚀 文中白话居多,尽量以小白…...
Helm Kubernetes Offline Deploy Rancher v2.7.5 Demo (helm 离线部署 rancher 实践)
文章目录 1. 简介2. 预备条件3. 选择 SSL 配置4. 离线安装的 Helm Chart 选项5. 下载介质6. 生成证书7. 镜像入库8. 安装 rancher9. 配置 nodeport10. 配置 ingress11. 界面访问11.1 首页预览11.2 查看集群信息11.3 查看项目空间11.4 查看节点信息 1. 简介 Rancher 是一个开源…...
网络编程day6——基于C/S架构封装的线程池
一、线程竞争基本概念 竞争与同步 同一个进程中的线程共享进程中的绝大多数资源,当它们随意竞争时可能会导致资源被破坏、脏数据、不完整问题 通过一些手段让线程在竞争资源时相互协调、避免出现以上问题,这就称为线程同步 原子操作: 操作过程…...
ARM/X86工业级数据采集 (DAQ) 与控制产品解决方案
I/O设备,包括信号调理模块、嵌入式PCI/PCIE卡、便携式USB模块、DAQ嵌入式计算机、模块化DAQ系统,以及DAQNavi/SDK软件开发包和DAQNavi/MCM设备状态监测软件。 工业I/O产品适用于各种工业自动化应用,从机器自动化控制、测试测量到设备状态监测…...
【Java】Jxls--轻松生成 Excel
1、介绍 Jxls 是一个小型 Java 库,可以轻松生成 Excel 报告。Jxls 在 Excel 模板中使用特殊标记来定义输出格式和数据布局。 Java 有一些用于创建 Excel 文件的库,例如Apache POI。这些库都很好,但都是一些较底层的库,因为它们要…...
MySQL主从复制读写分离
读写分离 读写分离,基本的原理是让主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库处理SELECT查询操作。数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库 读写分离的好处 因为数据库的“写…...
Kafka3.0.0版本——消费者(手动提交offset)
目录 一、消费者(手动提交 offset)的概述1.1、手动提交offset的两种方式1.2、手动提交offset两种方式的区别1.3、手动提交offset的图解 二、消费者(手动提交 offset)的代码示例2.1、手动提交 offset(采用同步提交的方式…...
【AIGC专题】Stable Diffusion 从入门到企业级实战0403
一、前言 本章是《Stable Diffusion 从入门到企业级实战》系列的第四部分能力进阶篇《Stable Diffusion ControlNet v1.1 图像精准控制》第03节, 利用Stable Diffusion ControlNet Canny模型精准控制图像生成。本部分内容,位于整个Stable Diffusion生态…...
linux提权
目录 一、linux提权靶场下载与安装 二、基础提权 1.sudo提权 2.suid提权 3.taskset执行bash 三、内核提权 相关网站 https://gtfobins.github.io/#sudohttps://blog.csdn.net/weixin_43873557/article/details/113784146 一、linux提权靶场下载与安装 #下载链接 http…...
Excel VSTO开发7 -可视化界面开发
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 7 可视化界面开发 前面的代码都是基于插件启动或者退出时,以及Excel Application的相关事件,在用户实际操作…...
英文科技论文写作与发表-投稿到发表(第6章)
1 投稿到发表 本章介绍典型会议和期刊从投稿到最终录用或退稿的全过程,期刊从投稿到最终录用或退稿的过程在各种不同学科领域差别不大。会议主要针对计算机科学及其相关领域(如电子、信息、其他工程类)的会议。最后总结几条怎样提高论文命中…...
2.4.3 【MySQL】设置系统变量
2.4.3.1 通过启动选项设置 大部分的系统变量都可以通过启动服务器时传送启动选项的方式来进行设置。如何填写启动选项就是下面两种方式: 通过命令行添加启动选项。 在启动服务器程序时用这个命令: mysqld --default-storage-engineMyISAM --max-conn…...
【Redis】2、Redis持久化和性能管理
Redis 高可用 在web服务器中,高可用是指服务器可以正常访问的时间,衡量的标准是在多长时间内可以提供正常服务(99.9%、99.99%、99.999%等等)。 但是在Redis语境中,高可用的含义似乎要宽泛一些,除了保证提供…...
MIT6.S081实验环境搭建
MIT6.S081 lab 环境搭建 本文参考了MIT的官方指南和知乎文章环境搭建 step1 首先需要一个ubuntu20.04的系统,我使用的是vscode的WSL2连接的ubuntu20.04,使用virtual box建一个ubuntu20.04的虚拟机应该也可以。 可以用 lsb_release -a 查看一下自己ub…...
spring spring-boot spring-cloud spring-cloud-alibaba之间版本对应关系
spring 版本与 jdk 的对应关系 https://github.com/spring-projects/spring-framework/wiki/Spring-Framework-Versions 从 spring 6.0 开始使用 jdk 17 进行编译 对应的相关 servlet 容器(tomcat、undertow、jetty等)的 servlet 规范转移到 eclipse&…...
Docker技术入门 | Part01:Docker简介
文章目录 1 虚拟化技术2 Docker概述2.1 Docker能解决的问题2.2 Docker介绍2.3 为什么使用Docker2.4 Docker特点2.5 Docker应用场景 3 Docker与虚拟机对比3.1 Docker和虚拟机组成结构3.2 Docker和虚拟机的不同点 4 Docker基本概念4.1 Docker引擎4.2 Docker基本架构4.3 Docker容器…...
Apache实现weblogic集群配置
安装apache,安装相对稳定的版本。如果安装后测试能否正常启动,可以通过访问http://localhost/进行测试。安装Weblogic,参见文档将bea安装目录 weblogic81/server/bin 下的 mod_wl_20.so 文件copy到 apache安装目录下Apache2/modules/目录下A…...
Java面试题总结2023
Java面试题总结2023 基础String中常用的方法 与 equals的区别值传递和引用传递数组和集合的区别成员变量和局部变量的区别final和finally和finalize的区别Cookie和Session的的区别接口分类接口和抽象类的区别说说你对抽象类的理解String/StringBuffer/StringBuilderjdk1.8的新特…...
采用ROUANT 方法对 nex-gddp-cmip6 数据进行精度校正
专题一 CMIP6中的模式比较计划 1.1 GCM介绍全球气候模型(Global Climate Model, GCM),也被称为全球环流模型或全球大气模型,是一种用于模拟地球的气候系统的数值模型。这种模型使用一系列的数学公式来描述气候系统的主要组成部分…...
超级电容-电池-超级电容混合储能系统能量管理simulink仿真建模模型
建立混合储能系统模型 在Simulink中,首先需要建立一个超级电容和蓄电池并联的混合储能系统模型。其中,超级电容和蓄电池的荷电状态(SOC)需要根据实际情况进行管理。荷电状态可以通过对电池和超级电容的电压、电流等进行测量&…...
最新仿闲鱼链接+独立后台管理 跳转APP
2024最新仿xy链接源码 后台一键生成链接,后台管理教程:解压源码,修改数据库config/Congig 不会可以看源码里有教程 下载程序:https://pan.baidu.com/s/16lN3gvRIZm7pqhvVMYYecQ?pwd6zw3...
DoIP协议——汽车以太网应用介绍
DoIP目录 前言一、DoIP术语和缩写二、网络拓扑三、DoIP数据基本结构四、应用场景4.1 直接点对点连接4.2 多台外部测试设备分别和多台汽车在局域网内通过交换机点对点连接4.3 一台外部测试设备跨越本地网络与多台车辆连接4.4 外部测试设备的多个应用层实体(在一台硬件或多台硬件…...
人个做外贸用什么网站好/推广app赚钱的平台
【计算机】数据结构-严蔚敏/清华大学P1 第一章 绪论 1.1数据结构讨论的范畴 1.2基本概念 1.3算法及其量度 1.1数据结构讨论的范畴 Niklaus Wirth Algorithm Data Structures Programs 程序设计:为计算机处理问题编制一组指令集 算法:处理问题的…...
网站建设定制设计/品牌推广策划方案案例
iwconfig命令用于系统配置无线网络设备或显示无线网络设备信息。iwconfig命令类似于ifconfig命令,但是他配置对象是无线网卡,它对网络设备进行无线操作,如设置无线通信频段。auto 自动模式essid 设置ESSIDnwid 设置网络IDfreq 设置无线网络通…...
可以做网站高仿服装吗/重庆广告公司
不限(学硕)(0101)哲学(学硕)(0201)理论经济学(学硕)(0202)应用经济学(专硕)(0251)金融硕士(专硕)(0252)应用统计硕士(专硕)(0253)税务硕士(专硕)(0254)国际商务硕士(专硕)(0255)保险硕士(专硕)(0256)资产评估硕士(专硕)(0257)审计硕士(学硕)(0270)统计学(学硕)(0301)法学(学硕)…...
家乡特产网络营销方案/天津关键词优化专家
1.在下列的 HTML 中,哪个可以添加背景颜色?()A.<body color"yellow">B.<background>yellow</background>C.<body bgcolor"yellow"> 2.在下列的 HTML 中,哪个可以插入背景…...
淮滨网站建设公司/东莞疫情最新消息今天新增
工具包请下载:http://pan.baidu.com/s/1gdwenSZ ICA网络流量测试使用 NetMeter工具安装在客户端上面,监控网络流量。方法与步骤:将客户端上面的所有应用程序关闭并退出,特别是迅雷,QQ等耗费网络流量的软件。确保客户端…...
专业手机网站建设公司排名/黑科技引流工具
Facebook 又收到一张罚单。 周四,欧盟反垄断部门决定对 Facebook 处以 1.1 亿欧元(约 8.43 亿元)的罚款,理由是在 WhatsApp 的收购案中,Facebook 提供了有误导性的不实信息。这个数字大约是 Facebook 一年营收额的 0.5…...