深度优先

这个家伙好懒,除了文章什么都没留下

0%

参考:https://github.com/TommyZihao/ZihaoTutorialOfRaspberryPi/blob/master/

系统安装

开机配置

  • 允许SSH连接

在boot目录下新建一个ssh文件,不带文件后缀

  • 配置wifi文件

用同样的方法新建一个空白文件wpa_supplicant.conf(注意要删掉扩展名.txt)

用文本编辑器打开wpa_supplicant.conf,输入以下配置,可以用多个network{}来配置多个wifi:

1
2
3
4
5
6
7
8
9
10
11
12
13
country=GB
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
ssid="将我替换成第一个WiFi的名字,不删除引号,不能有中文"
psk="将我替换成WiFi密码,不删除引号"
priority=将我替换成数字,数字越大代表优先级越高
}
network={
ssid="将我替换成第二个WiFi的名字,不删除引号,不能有中文"
psk="将我替换成WiFi密码,不删除引号"
priority=将我替换成数字,数字越大代表优先级越高
}

软件配置

用户配置

  • pi用户登录,默认密码为:raspberry
1
ssh pi@192.168.1.109
  • 启用root用户登录
1
2
3
sudo passwd root
sudo passwd --unlock root
su root
  • 修改pi的默认密码
1
sudo passwd pi
  • root用户远程登录
1
2
3
4
5
6
sudo nano /etc/ssh/sshd_config

# Ctrl + W 快捷键 搜索 PermitRootLogin without-password
# 修改 PermitRootLogin without-password 为 PermitRootLogin yes
# Ctrl + O 快捷键 保存
# Ctrl + O 快捷键 退出 Nano 编辑器

源配置

  • 换源,选择:bebian10 buster

https://mirrors.tuna.tsinghua.edu.cn/help/raspbian/

1
sudo nano /etc/apt/sources.list
  • 删除原文件所有内容,用以下内容取代:
1
2
deb [arch=armhf] http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ buster main non-free contrib rpi
deb-src http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ buster main non-free contrib rpi
1
sudo nano /etc/apt/sources.list.d/raspi.list
  • 删除原文件所有内容,用以下内容取代:
1
deb http://mirrors.tuna.tsinghua.edu.cn/raspberrypi/ buster main
  • 更新源
1
sudo apt-get update
  • 更新系统
1
sudo apt-get upgrade

安装Docker

  • 一键安装
1
curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun

MySql

  • 安装
1
2
3
4
docker run -p 3306:3306 --name mysql \
-v /opt/docker/mysql/conf:/etc/mysql/conf.d \
-v /opt/docker/mysql/logs:/var/log/mysql \
-v /opt/docker/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -d --restart=always ibex/debian-mysql-server-5.7
  • 配置
1
2
3
4
5
6
7
8
9
10
# 进入docker
docker exec -it mysql /bin/bash

# 进入mysql
mysql -uroot -proot

use mysql;

# 允许远程登录,修改密码
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'password' WITH GRANT OPTION;

Portainer

  • 安装
1
2
3
4
5
docker run -d -p 9000:9000 \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
--name portainer \
docker.io/portainer/portainer
  • 配置

访问:http://ip:9000

Redis

  • 安装

下载配置:https://raw.githubusercontent.com/redis/redis/6.0.8/redis.conf

1
2
3
4
docker run -it -d --sysctl net.core.somaxconn=1024 --name redis \
-v /opt/docker/redis/conf/redis.conf:/etc/redis/redis.conf \
-v /opt/docker/redis/data:/data -p 6379:6379 --privileged=true \
redis:6.0.8 redis-server /etc/redis/redis.conf
  • 配置

修改opt/docker/redis/conf/redis.conf

1
2
3
4
5
6
7
# 允许远程连接
# bind 127.0.0.1
protected-mode no
# 持久化
appendonly yes
# 密码
requirepass password

Mongo

  • 安装
1
2
3
4
5
docker run -d --name mongo -p 27017:27017  \
-v /opt/docker/mongo/data:/data/db \
-v /opt/docker/mongo/conf:/data/conf \
-v /opt/docker/mongo/log:/data/log \
andresvidal/rpi3-mongodb3 mongod --auth
  • 配置
1
2
3
4
5
6
7
8
9
10
11
12
# 进入docker
docker exec -it mongo mongo admin

# 创建用户
db.createUser({ user:'admin',pwd:'password',roles:[ { role:'userAdminAnyDatabase', db: 'admin'},"readWriteAnyDatabase"]});

# 测试用户登录
db.auth('admin', 'password');

# 测试
use testdb
db.testdb.insert({"name":"1111"})

nextcloud

  • 安装
1
2
3
4
5
6
docker run -d --name nextcloud -p 8080:80 \
-v /opt/docker/nextcloud/html:/var/www/html \
-v /opt/docker/nextcloud/apps:/var/www/html/custom_apps \
-v /opt/docker/nextcloud/config:/var/www/html/config \
-v /opt/docker/nextcloud/data:/var/www/html/data \
arm32v7/nextcloud:20.0.9-apache

版本20.0.9高版本可能不支持mysql5.7

  • 配置 /opt/docker/nextcloud/config/config.php

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    <?php
    $CONFIG = array (
    'htaccess.RewriteBase' => '/',
    'memcache.local' => '\\OC\\Memcache\\APCu',
    'filelocking.enabled' => true,
    'memcache.locking' => '\OC\Memcache\Redis', ### 配置Redis缓存
    'memcache.distributed' => '\OC\Memcache\Redis',
    'redis' => [
    'host' => '192.168.1.109',
    'port' => 6379,
    'dbindex' => 1,
    'password' => '*******',
    'timeout' => 2,
    ],
    'apps_paths' =>
    array (
    0 =>
    array (
    'path' => '/var/www/html/apps',
    'url' => '/apps',
    'writable' => false,
    ),
    1 =>
    array (
    'path' => '/var/www/html/custom_apps',
    'url' => '/custom_apps',
    'writable' => true,
    ),
    ),
    'instanceid' => 'ocvniiym4g94',
    'passwordsalt' => '*******',
    'secret' => 'IV+*******',
    'trusted_domains' =>
    array (
    0 => '192.168.1.109:8080',
    1 => 'nextcloud.bfsdfs.com'
    ),
    'datadirectory' => '/var/www/html/data',
    'dbtype' => 'mysql',
    'version' => '20.0.9.1',
    'overwrite.cli.url' => 'http://192.168.1.109:8080',
    'dbname' => 'nextcloud_db',
    'dbhost' => '192.168.1.109:3306',
    'dbport' => '',
    'dbtableprefix' => 'oc_',
    'mysql.utf8mb4' => true,
    'dbuser' => 'nextcloud',
    'dbpassword' => '**********',
    'installed' => true,
    'filesystem_check_changes' => true #自动扫描文件
    );
  • 配置MySql

1
2
3
4
5
6
### 创建数据库
CREATE DATABASE nextcloud_db;
### 创建用户
SET PASSWORD FOR 'nextcloud'@'%' = PASSWORD('******');
### 授权权限
GRANT ALL ON nextcloud_db.* TO 'nextcloud'@'%';

frpc

  • 安装
1
2
3
4
5
6
sudo cd /opt/docker/frp/
sudo wget https://github.com/fatedier/frp/releases/download/v0.39.1/frp_0.39.1_linux_arm.tar.gz
sudo tar -zxvf frp_0.39.1_linux_arm.tar.gz
sudo rm frp_0.39.1_linux_arm.tar.gz
sudo mv frp_0.39.1_linux_arm /opt/docker/frp
sudo ./frpc -c ./frpc.ini
  • 配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[common]
server_addr = ****
# 修改成公网ip
server_port = 8888
privilege_token = ******
pool_count = 2
log_file = ./frpc.log
log_level = info
log_max_days = 10

# 访问用户,与服务端用户配置文件名一致
# 与服务端用户配置文件中的token保持一致
token = *******

[xxx]
type = tcp
local_port = 9000
local_ip = 127.0.0.1
remote_port = 9000
  • 配置服务
1
2
cd /opt/docker/frp
./frpc -c ./frpc.ini
1
sudo nano /lib/systemd/system/frpc.service
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[Unit]
Description=Frp Client Service
After=network.target

[Service]
Type=simple
User=nobody
Restart=on-failure
RestartSec=5s
ExecStart=/opt/docker/frp/frpc -c /opt/docker/frp/frpc.ini
ExecReload=/opt/docker/frp/frpc reload -c /opt/docker/frp/frpc.ini
LimitNOFILE=1048576

[Install]
WantedBy=multi-user.target
1
2
3
4
sudo systemctl daemon-reload
sudo systemctl enable frpc
sudo systemctl start frpc
sudo systemctl status frpc

转自:https://www.cnblogs.com/tiger-wang/p/14068973.html

前言

今天给大家分享一个微软官方的生产者/消费者方案的特性解决:Channel。

Channel在System.Threading.Channels命名空间下,Core 2.1使用时,需要从Nuget上安装。

1
% dotnet add package System.Threading.Channels

而在Core 3.0 preview 7开始,就直接包含在框架中了。

这是一个相对较新的特性。从Core 2.1开始加入,现在版本是5.0.0(嗯,这个版本号有点骗人,Channel的第一个版本就是4.5.0)。

Channel能做什么?

逻辑上,Channel实际就是一个高效的、线程安全的队列,支持在生产者和消费者之间传递数据。

利用Channel,通过发布和订阅,可以将生产者和消费者分开。生产者Producer负责接收请求,并写入Channel,而消费者Consumer为每个进入Channel的数据执行处理。这样做,一方面可以使生产者和消费者并行工作来提高性能,另一方面,可以通过创建更多的生产者或消费者来提高应用的吞吐量。

下面,我们以一个实际例子,来解释这个特性。

创建Channel

Channel提供了一个静态Channel类,提供了两个公开方法来创建两种类型的Channel。

  • CreateUnbounded - 创建一个具有无限容量的Channel。

  • CreateBounded - 创建一个具有有限容量的Channel。

人通常来说,这两种方式使用上没有太大的区别。实际应用中,具体要看生产和消费的速度,以及期望产生的结果。有限容量的Channel,容量是有上限的,到达上限后,可以让生产者非阻塞等待消费者使用并释放Channel容量后再继续。这种方式,好处是可以控制生产的速度,控制系统资源的使用,缺点也是。因为控制速度意味着生产速度会被限制,甚至停止。而无限容量,生产者可以全速进行生产。但也有缺点,如果消费者的消费速度低于生产者,Channel的资源使用会无限增加,会有服务器资源耗尽的可能。

今天的例子,我们使用无限Channel。

1
var channel = Channel.CreateUnbounded<string>();

非常简单的一行代码,就创建了一个无限容量的Channel。

我们定义这个Channel用来保存字符串对象。

创建方法是一个通用的工厂方法,所以我们可以为需要使用的任何类型的对象和数据创建Channel。

Channel有两个属性:阅读器返回ChannelReader,写入器返回ChannelWriter。

写入Channel

使用写入器ChannelWriter,可以对Channel进行写入操作。ChannelWriter提供了以下几个方法:

  • WriteAsync - 异步写入
  • WaitToWriteAsync - 非阻塞等待,直到有空间可写入时或Channel关闭时,返回true/false
  • TryWrite - 尝试写入
  • Complete - 标记Channel为关闭,并不再写入数据到该Channel
  • TryComplete - 尝试标记Channel为关闭。

这几个方法很容易理解,就不解释了。

在本文的例子里,我用了:

1
await channel.Writer.WriteAsync("New message");

读取Channel

使用阅读器ChannelReader从Channel进行数据的读取。也提供了几个方法:

  • ReadAsync - 异步读取
  • ReadAllAsync - 异步读取Channel中的所有数据
  • TryRead - 尝试读取
  • WaitToReadAsync - 非阻塞等待,直到有数据可读取或Channel关闭时,返回true/false

不同的消费者模式,会用到不同的读取方法。这个根据经验来写就好。

本文的例子中,我是采用WaitToReadAsync和ReadAsync配合来使用的:

1
2
3
4
5
6
7
while (await ChannelReader.WaitToReadAsync())
{
if (ChannelReader.TryRead(out var timeString))
{
/***/
}
}

WaitToReadAsync是一个非阻塞等待,在有消息可读或Channel关闭时,才会唤醒并继续。

考虑到有多个消费者的情况,有可能别的线程已经进行了读取,这儿使用TryRead进行读取操作。

要注意:数据的同步工作是由Channel进行管理的。Channel会确保多个消费者不会读到相同的数据。Channel同时也管理数据的次序。

示例代码

今天的示例代码我放到了Github上。链接是文章最后。

这个例子中,我做了三个场景。

首先是Channel。我使用了无限Channel。然后是创建生产者和消费者。数据传输过程就简单化了,生产者只简单将一个字符串写入到Channel。消费者也是,简单等待并从Channel读取数据字符串,写入控制台。

三个场景分别是:

单一生产者/单一消费者

这个例子中,创建了一个生产者和一个消费者。两者的任务都是并发启动的。

里面的延时,是用来模拟工作负载的。

多个生产者/单一消费者

这个例子中有两个生产者。通常在应用中有多个生产者时,我们需要确保生产与单个消费者所能处理的消息数量大致相当,这样能更好地利用服务器资源。

单一生产者/多个消费者

这个其实是应用中最常见的情况,就是产生消息很快,但处理工作相关较慢,而且工作也更密集。这种情况,实际应用中我们可以通过扩大消费者数量来满足生产的需求。

总结

最近的项目在做一个大数据的采集,用到了一些Channel的技术。然后发现网上这部分内容很少,就做了个例子,写了这个文章。

Channel内容本身并不多,但用着很方便,而且实际应用中,比想像的更强大。它可以简化很多生产者/消费者模式的使用,而且,任务间交换数据,使用Channel会更方便,更直接。

示例代码在:https://github.com/humornif/Demo-Code/tree/master/0033/demo

转自:https://www.cnblogs.com/Can-daydayup/p/11610747.html

前言:

  定时任务调度问题,是一个老生常谈的问题。网上有许多定时任务调度的解决方案,对于我而言很早以前主要是使用Window计划和Window服务来做任务定时执行,然后就开始使用定时任务调度框架Quartz.Net。但是却一直没有上手过Hangfire这个自带后台任务调度面板,可以在后台手动执行任务的神奇的任务调度框架。前段时间终于开始对他下手了,通过在网上查阅了一些资料和查看了Hangfire在Github中的demo,终于在我自己的项目中用上了Hangfire。在该篇文章中主要简单介绍一下什么是Hangfire,Hangfire的基本特征与优点和分别使用MySQL,MS SQL Server作为存储使用。

Hangfire是什么:

  Hangfire是一个开源的.NET任务调度框架,提供了内置集成化的控制台,可以直观明了的查看作业调度情况,并且Hangfire不需要依赖于单独的应用程序执行(如:windows服务,window计划)。并且支持持久性存储。

Hangfire使用条件:

Hangfire与特定的.NET应用程序类型无关。您可以在ASP.NET Web应用程序,非ASP.NET Web应用程序,控制台应用程序或Windows服务中使用它。以下是要求:

1.NET Framework 4.5

2.永久存储(Hangfire将后台作业和其他与处理有关的信息保留在永久性存储器中,所以需要存储库来存储如:MS SQL Server,Redis,MySQL,PostgreSql等)

3.Newtonsoft.Json库≥5.0.1

Hangfire的基本特征与优点:

通过官网中的一张图片便可知道它是一个多么优秀的任务调度框架,如下图所示:

Hangfire安装和使用:

在NuGet上有关于Hangfire的 一系列软件包:

详情地址: https://www.nuget.org/packages?q=Hangfire

通过在程序包管理控制台中输入安装命令安装Hangfire所需NuGet包:

使用MS SQL Server作为存储时我们需要安装的NuGet:

在ASP.NET 应用程序下使用Hangfire安装:

1
Install-Package Hangfire

在控制台应用程序或者window server中处理作业:

1
2
Install-Package Hangfire.Core
Install-Package Hangfire.SqlServer

注意,在控制台应用程序或者window server中不推荐直接安装:Install-Package Hangfire ,因为它只是一个快速启动软件包,并包含您可能不需要的依赖项(例如,Microsoft.Owin.Host.SystemWeb等无关依赖项)。

使用MySQL作为存储时我们需要安装的NuGet:

在ASP.NET 应用程序下使用Hangfire安装:

1
Install-Package Hangfire.Core

我们还需要安装一个MySql存储(Hangfire.MySqlStorage)的拓展,注意因为Hangfire本身是不支持MySQL存储的,这是名为:Arnoldas Gudas作者拓展的:

Nuget地址:https://www.nuget.org/packages/Hangfire.MySqlStorage/

安装命令:

注意:因为我的项目是.NET Framework,Version=v4.5.1版本的,所以只能安装1.0.7版本的,大家看需求而定

1
Install-Package Hangfire.MySqlStorage -Version 1.0.7

当我们要使用(宿主)IIS托管ASP.NET应用程序时,我们还需要安装:

1
Install-Package Microsoft.Owin.Host.SystemWeb -Version 4.0.1

添加和配置OWIN Startup.cs,及其连接对应的存储数据库:

添加OWIN Startup.cs

这里是当你的项目中不存在Startup.cs时才需要执行添加的操作!

什么是OWIN Startup.cs:

简单概述:是.NET 平台开放的web接口,Startup则是.Net与web通讯管道,起到转发,沟通的作用。

详情介绍:https://www.cnblogs.com/wj033/p/6065145.html

在Startup.cs中连接需要使用的存储库:

1
2
3
4
5
6
7
8
9
10
11
12
13
public void Configuration(IAppBuilder app)
{
//运用SqlServer存储,对应web.config中的connectionStrings中的name
GlobalConfiguration.Configuration.UseSqlServerStorage("sqlserver_connection");<br>

//注意,当你使用的是MySql作为存储时,需要如下配置
//运用MySql存储,对应web.config中的connectionStrings中的name
GlobalConfiguration.Configuration.UseStorage(new MySqlStorage("mysql_connection"));

app.UseHangfireDashboard();//配置后台仪表盘
app.UseHangfireServer();//开始使用Hangfire服务

}

Web.config数据库连接配置:

1.MS SQL Server中:

1
2
3
<connectionStrings>
<add name="sqlserver_connection" connectionString="Data Source=.;Initial Catalog=MyFirstDb;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>

2.MySQL中:

1
2
3
<connectionStrings>
<add name="mysql_connection" providerName="System.Data.MySqlClient" connectionString="Server=123.xxx.xxx.xx;Port=3306;Database=MyFirstDb;Uid=root;Pwd=youpassword;charset=utf8;SslMode=none;Allow User Variables=True" />
</connectionStrings>

运行程序,访问调度控制面板:

  当我们已经完成了上面的相关配置后,且程序能够正常无bug的运行时,我们的Hangfire Dashboard(仪表盘)在我们的本地就可以正常访问了(Hangfire仪表盘默认只支持本地访问),假如需要远程可访问的话我们还需要做对应的配置授权操作!

运行成功,查看数据库中是否生成了与Hangfire相关的表:

  首次运行成功后,打开数据库可以看到Hangfire已经自动为我们创建了定时任务的一些定时任务列表,定时队列,服务,状态等相关的数据表(展现了Hangfire作用的持久化特性),如下图所示:

a.MS SQL Server中生成的表:

b.MySQL中生成的表:

访问调度控制面板:

本地访问方式:https://localhost:端口号/hangfire/

调度控制面板效果图:

后台常用任务调度创建和使用:

注意:WriteLog是自己封装的一个通用记录日志的方法!

1
2
3
4
5
6
7
8
9
10
11
//支持基于队列的任务处理:任务执行不是同步的,而是放到一个持久化队列中,以便马上把请求控制权返回给调用者。
var jobId = BackgroundJob.Enqueue(()=>WriteLog("队列任务执行了!"));

//延迟任务执行:不是马上调用方法,而是设定一个未来时间点再来执行,延迟作业仅执行一次
var jobId = BackgroundJob.Schedule(()=>WriteLog("一天后的延迟任务执行了!"),TimeSpan .FromDays(1));//一天后执行该任务

//循环任务执行:一行代码添加重复执行的任务,其内置了常见的时间循环模式,也可基于CRON表达式来设定复杂的模式。【用的比较的多】
RecurringJob.AddOrUpdate(()=>WriteLog("每分钟执行任务!"), Cron.Minutely); //注意最小单位是分钟

//延续性任务执行:类似于.NET中的Task,可以在第一个任务执行完之后紧接着再次执行另外的任务
BackgroundJob.ContinueWith(jobId,()=>WriteLog("连续任务!"));

总结:

  通过本次项目实践的确让我感受到了Hangfire的魅力所在,真的可以说是上手简单,开箱即用的一个任务调度框架。并且该框架做的最好的是,官方文档详细,并且还提供了完整的demo示例。最后要为Hangfire的作者点赞!

Hangfire相关使用学习资料:

官网地址:https://www.hangfire.io/

GitHub源码:https://github.com/HangfireIO/Hangfire

中文文档:https://www.bookstack.cn/read/Hangfire-zh-official/README.md

GitHub使用示例源码:https://github.com/HangfireIO/Hangfire.Samples(包括控制台应用程序,window服务,ASP.NET MVC,WebForm)

Hangfire使用文章汇总:https://www.bbsmax.com/R/xl56E0nrJr/