当前位置: 首页 > 编程日记 > 正文

Akka源码分析-Remote-发消息

上一篇博客我们介绍了remote模式下Actor的创建,其实与local的创建并没有太大区别,一般情况下还是使用LocalActorRef创建了Actor。那么发消息是否意味着也是相同的呢?

既然actorOf还是委托给了LocalActorRef,那么在本地创建的Actor发消息还是跟以前一样的,那么如果如何给远程的Actor发消息呢?我们一般是通过actorSelection或者给远程Actor发送一个Identify消息,来接收对应的ActorRef,然后再发消息。我们来分析一下这两者的区别。

首先来看actorSelection,不管是用ActorSystem或者ActorContext的actorSelection方法,最终都是调用了ActorRefFactory对应的方法。

/*** Construct an [[akka.actor.ActorSelection]] from the given path, which is* parsed for wildcards (these are replaced by regular expressions* internally). No attempt is made to verify the existence of any part of* the supplied path, it is recommended to send a message and gather the* replies in order to resolve the matching set of actors.*/def actorSelection(path: String): ActorSelection = path match {case RelativeActorPath(elems) ⇒if (elems.isEmpty) ActorSelection(provider.deadLetters, "")else if (elems.head.isEmpty) ActorSelection(provider.rootGuardian, elems.tail)else ActorSelection(lookupRoot, elems)case ActorPathExtractor(address, elems) ⇒ActorSelection(provider.rootGuardianAt(address), elems)case _ ⇒ActorSelection(provider.deadLetters, "")}

我们发现它支持两种类型的path:RelativeActorPath、ActorPathExtractor。

/*** Extractor for so-called “relative actor paths” as in “relative URI”, not in* “relative to some actor”. Examples:**  * "grand/child"*  * "/user/hello/world"*/
object RelativeActorPath extends PathUtils {def unapply(addr: String): Option[immutable.Seq[String]] = {try {val uri = new URI(addr)if (uri.isAbsolute) Noneelse Some(split(uri.getRawPath, uri.getRawFragment))} catch {case _: URISyntaxException ⇒ None}}
}

RelativeActorPath提取器比较简单,就是创建了一个URI对象,然后判断其是否为Absolute,如果是就返回None,如果不是就返回对应的elemes。对于远程Actor,我们一般会指定主机名、端口号,例如akka.tcp://actorSystemName@10.0.0.1:2552/user/actorName,根据URI的定义,这个URI的schema是akka.tcp,很显然是Absolute,那就会返回None。

/*** Given an ActorPath it returns the Address and the path elements if the path is well-formed*/
object ActorPathExtractor extends PathUtils {def unapply(addr: String): Option[(Address, immutable.Iterable[String])] =try {val uri = new URI(addr)uri.getRawPath match {case null ⇒ Nonecase path ⇒ AddressFromURIString.unapply(uri).map((_, split(path, uri.getRawFragment).drop(1)))}} catch {case _: URISyntaxException ⇒ None}
}

ActorPathExtractor这个提取器的名称定义的是有问题的,既然actorSelection只支持两种类型的路径选择:本地和远程。第一个解析器定义成相对路径,那么后面一个就直接是绝对路径好了啊,为啥用ActorPathExtractor这样蹩脚的命名?难道本地模式下,就不是ActorPath提取器了?我们来看看对于akka.tcp://actorSystemName@10.0.0.1:2552/user/actorName提取出了什么。经调试,address是akka.tcp://actorSystemName@10.0.0.1:2552,elems就是后面的user、actorName了。

也就是说remote模式下,如果有host、prot等信息就会返回ActorSelection(provider.rootGuardianAt(address), elems)这个类。不过好像无论哪种情况都返回这个类,好尴尬啊,但传入的第一个参数是不同的:provider.rootGuardianAt(address)。也就是说actorSelection这个函数是不区分当前的模式的,只要含有host/port就会传入provider.rootGuardianAt(address),否则就传入provider.rootGuardian。如果在local模式下,也强制用actorSelection查找远程Actor会发生什么呢?我们来看看LocalActorRefProvider。

  override def rootGuardianAt(address: Address): ActorRef =if (address == rootPath.address) rootGuardianelse deadLetters

local模式下,如果待查询actor的地址就是本地地址,则直接在本地返回查找;否则就返回deadLetters。其实是无法查找远程actor的。那么RemoteActorRefProvider呢?

def rootGuardianAt(address: Address): ActorRef = {if (hasAddress(address)) rootGuardianelse try {new RemoteActorRef(transport, transport.localAddressForRemote(address),RootActorPath(address), Nobody, props = None, deploy = None)} catch {case NonFatal(e) ⇒log.error(e, "No root guardian at [{}]", address)new EmptyLocalActorRef(this, RootActorPath(address), eventStream)}}

当然了,它也会判断一下本地地址是否包含待查询地址(防止多网卡或其他特殊情况),如果包含,则意味着是本地Actor交给rootGuardian;否则就创建RemoteActorRef。

分析到这里我们知道了,其实在remote模式下,actorSelection返回了一个RemoteActorRef,还记得这个类的作用嘛?我们之前简单分析过,它其实是对远程Acotor的一个本地网络代理,也就是说所有通过actorSelection发送给远程actor的消息,都会经过他中转。

我们继续分析ActorSelection的源码

/*** Construct an ActorSelection from the given string representing a path* relative to the given target. This operation has to create all the* matching magic, so it is preferable to cache its result if the* intention is to send messages frequently.*/def apply(anchorRef: ActorRef, elements: Iterable[String]): ActorSelection = {val compiled: immutable.IndexedSeq[SelectionPathElement] = elements.collect({case x if !x.isEmpty ⇒if ((x.indexOf('?') != -1) || (x.indexOf('*') != -1)) SelectChildPattern(x)else if (x == "..") SelectParentelse SelectChildName(x)})(scala.collection.breakOut)new ActorSelection with ScalaActorSelection {override val anchor = anchorRefoverride val path = compiled}}

很显然这里的anchorRef是上面创建的RemoteActorRef实例,其中ActorSelection的anchor(锚定)是anchorRef。至此,一个ActorSelection创建完毕。那么如何发消息呢?这就需要分析tell或者!方法了。

  def tell(msg: Any, sender: ActorRef): Unit =ActorSelection.deliverSelection(anchor.asInstanceOf[InternalActorRef], sender,ActorSelectionMessage(msg, path, wildcardFanOut = false))

其实乍一看,我们应该明白,这就是在deliverSelection函数内部,把消息封装成ActorSelectionMessage发送给了anchor。

该函数首先判断sel的elements是否为空,很显然不为空,进入rec函数。该函数比较复杂而且还是一个尾递归函数,但我们知道此处的ref就是RemoteActorRef,那么RemoteActorRef是不是一个ActorRefWithCell呢?

private[akka] class RemoteActorRef private[akka] (remote:                RemoteTransport,val localAddressToUse: Address,val path:              ActorPath,val getParent:         InternalActorRef,props:                 Option[Props],deploy:                Option[Deploy])extends InternalActorRef with RemoteRef 

那么rec就会走到case _的逻辑,也就是把消息转发给了前面创建的RemoteActorRef,我们来看看这个示例是如何实现tell的。

override def !(message: Any)(implicit sender: ActorRef = Actor.noSender): Unit = {if (message == null) throw InvalidMessageException("Message is null")try remote.send(message, OptionVal(sender), this) catch handleException(message, sender)}

RemoteActorRef这个类,通过remote把消息发送出去了,那么remote是什么呢?RemoteTransport是不是很熟悉?在ActorSystem启动的时候我们分析过这个对象,它是Remoting类的实例,Remoting里面send方法是怎样的呢?

override def send(message: Any, senderOption: OptionVal[ActorRef], recipient: RemoteActorRef): Unit = endpointManager match {case Some(manager) ⇒ manager.tell(Send(message, senderOption, recipient), sender = senderOption getOrElse Actor.noSender)case None          ⇒ throw new RemoteTransportExceptionNoStackTrace("Attempted to send remote message but Remoting is not running.", null)}

它又把消息转发给了manager,而manager就是endpointManager。endpointManager是不是也比较眼熟呢?前面文章中我们也见到过,这是一个EndpointManager实例,而EndpointManager是一个Actor。请注意这里用Send又对message进行了封装。EndpointManager是如何对Send消息进行反应的呢?

case s @ Send(message, senderOption, recipientRef, _) ⇒val recipientAddress = recipientRef.path.addressdef createAndRegisterWritingEndpoint(): ActorRef = {endpoints.registerWritableEndpoint(recipientAddress,uid = None,createEndpoint(recipientAddress,recipientRef.localAddressToUse,transportMapping(recipientRef.localAddressToUse),settings,handleOption = None,writing = true))}endpoints.writableEndpointWithPolicyFor(recipientAddress) match {case Some(Pass(endpoint, _)) ⇒endpoint ! scase Some(Gated(timeOfRelease)) ⇒if (timeOfRelease.isOverdue()) createAndRegisterWritingEndpoint() ! selse extendedSystem.deadLetters ! scase Some(Quarantined(uid, _)) ⇒// timeOfRelease is only used for garbage collection reasons, therefore it is ignored here. We still have// the Quarantined tombstone and we know what UID we don't want to accept, so use it.createAndRegisterWritingEndpoint() ! scase None ⇒createAndRegisterWritingEndpoint() ! s}

分析以上逻辑,简单来看,会先判断是不是存在一个endpoint,如果存在说明链接已经建立,可以直接发送,否则出于其他状态,就重新创建endpoint,然后把消息转发给该endpoint。

def registerWritableEndpoint(address: Address, uid: Option[Int], endpoint: ActorRef): ActorRef =addressToWritable.get(address) match {case Some(Pass(e, _)) ⇒throw new IllegalArgumentException(s"Attempting to overwrite existing endpoint [$e] with [$endpoint]")case _ ⇒// note that this overwrites Quarantine marker,// but that is ok since we keep the quarantined uid in addressToRefuseUidaddressToWritable += address → Pass(endpoint, uid)writableToAddress += endpoint → addressendpoint}

registerWritableEndpoint没有太复杂的逻辑,就是查询addressToWritable这个HashMap,如果不存在则把对应的endpoint加入缓存,并返回endpoint。而endpoint是通过createEndpoint创建的。

private def createEndpoint(remoteAddress:    Address,localAddress:     Address,transport:        AkkaProtocolTransport,endpointSettings: RemoteSettings,handleOption:     Option[AkkaProtocolHandle],writing:          Boolean): ActorRef = {require(transportMapping contains localAddress, "Transport mapping is not defined for the address")// refuseUid is ignored for read-only endpoints since the UID of the remote system is already known and has passed// quarantine checksval refuseUid = endpoints.refuseUid(remoteAddress)if (writing) context.watch(context.actorOf(RARP(extendedSystem).configureDispatcher(ReliableDeliverySupervisor.props(handleOption,localAddress,remoteAddress,refuseUid,transport,endpointSettings,AkkaPduProtobufCodec,receiveBuffers)).withDeploy(Deploy.local),"reliableEndpointWriter-" + AddressUrlEncoder(remoteAddress) + "-" + endpointId.next()))else context.watch(context.actorOf(RARP(extendedSystem).configureDispatcher(EndpointWriter.props(handleOption,localAddress,remoteAddress,refuseUid,transport,endpointSettings,AkkaPduProtobufCodec,receiveBuffers,reliableDeliverySupervisor = None)).withDeploy(Deploy.local),"endpointWriter-" + AddressUrlEncoder(remoteAddress) + "-" + endpointId.next()))}

createEndpoint最终创建了ReliableDeliverySupervisor这个Actor,也就是说RemoteActorRef最终又把消息发送给了ReliableDeliverySupervisor,ReliableDeliverySupervisor收到消息去调用handleSend方法。

  private def handleSend(send: Send): Unit =if (send.message.isInstanceOf[SystemMessage]) {val sequencedSend = send.copy(seqOpt = Some(nextSeq()))tryBuffer(sequencedSend)// If we have not confirmed the remote UID we cannot transfer the system message at this point just buffer it.// GotUid will kick resendAll() causing the messages to be properly written.// Flow control by not sending more when we already have many outstanding.if (uidConfirmed && resendBuffer.nonAcked.size <= settings.SysResendLimit)writer ! sequencedSend} else writer ! send

除去特殊情况,用户发的普通消息又发送给了writer,艾玛我去,真是绕啊。writer是什么呢?

var writer: ActorRef = createWriter()

private def createWriter(): ActorRef = {context.watch(context.actorOf(RARP(context.system).configureDispatcher(EndpointWriter.props(handleOrActive = currentHandle,localAddress = localAddress,remoteAddress = remoteAddress,refuseUid,transport = transport,settings = settings,AkkaPduProtobufCodec,receiveBuffers = receiveBuffers,reliableDeliverySupervisor = Some(self))).withDeploy(Deploy.local), "endpointWriter"))}

很显然这又是一个ACor!!!哎,继续查找EndpointWriter这个Actor喽

def receive = if (handle.isEmpty) initializing else writing

val writing: Receive = {case s: Send ⇒if (!writeSend(s)) {enqueueInBuffer(s)scheduleBackoffTimer()context.become(buffering)}// We are in Writing state, so buffer is empty, safe to stop herecase FlushAndStop ⇒flushAndStop()case AckIdleCheckTimer if ackDeadline.isOverdue() ⇒trySendPureAck()}

这个Actor会先判断是否已经初始化,这里就假设初始化吧,初始化之后就会进入writing这个偏函数,对send类型的消息,又调用了writeSend函数。

这个函数简单来看,就是调用codec对消息进行序列化,然后创建了一个pdu,最终把pdu通过handle的write发送出去。handle又是什么呢?

var handle: Option[AkkaProtocolHandle] = handleOrActive

private[remote] class AkkaProtocolHandle(_localAddress:          Address,_remoteAddress:         Address,val readHandlerPromise: Promise[HandleEventListener],_wrappedHandle:         AssociationHandle,val handshakeInfo:      HandshakeInfo,private val stateActor: ActorRef,private val codec:      AkkaPduCodec)extends AbstractTransportAdapterHandle(_localAddress, _remoteAddress, _wrappedHandle, AkkaScheme) {override def write(payload: ByteString): Boolean = wrappedHandle.write(codec.constructPayload(payload))override def disassociate(): Unit = disassociate(Unknown)def disassociate(info: DisassociateInfo): Unit = stateActor ! DisassociateUnderlying(info)
}

handle最终是一个AkkaProtocolHandle,这个对象我们不再具体分析,我们可以认为这是一个本地与远程地址链接的通道,通过这个通道就可以与远程actor发送消息了。

分析到这个地方,actorSelection与远程通信的过程大概就梳理清楚了。为了方便理解,作者特意辛苦的画了一个流程图,以供参考。细心的读者一定会问,那我的消息通过handle发送出去了,对方怎么接收呢?接收之后怎么发送到指定actor的邮箱呢?这一点我们后面再分析。

actorSelection分析清楚了,剩下的就是通过ActorRef发送消息了。那么如何得到远程Actor的ActorRef呢?当然是“问”它了啊,怎么“问”呢?发消息啊。发什么消息呢?

/*** A message all Actors will understand, that when processed will reply with* [[akka.actor.ActorIdentity]] containing the `ActorRef`. The `messageId`* is returned in the `ActorIdentity` message as `correlationId`.*/
@SerialVersionUID(1L)
final case class Identify(messageId: Any) extends AutoReceivedMessage with NotInfluenceReceiveTimeout

官网对Identify的注释非常清楚,这个消息继承了AutoReceivedMessage,所有的Actor都理解该消息,且受到该消息后会返回akka.actor.ActorIdentity消息,里面包含当前Actor的ActorRef。那么所有的Actor为啥都理解该消息呢?

//Memory consistency is handled by the Mailbox (reading mailbox status then processing messages, then writing mailbox statusfinal def invoke(messageHandle: Envelope): Unit = {val influenceReceiveTimeout = !messageHandle.message.isInstanceOf[NotInfluenceReceiveTimeout]try {currentMessage = messageHandleif (influenceReceiveTimeout)cancelReceiveTimeout()messageHandle.message match {case msg: AutoReceivedMessage ⇒ autoReceiveMessage(messageHandle)case msg                      ⇒ receiveMessage(msg)}currentMessage = null // reset current message after successful invocation} catch handleNonFatalOrInterruptedException { e ⇒handleInvokeFailure(Nil, e)} finally {if (influenceReceiveTimeout)checkReceiveTimeout // Reschedule receive timeout}}def autoReceiveMessage(msg: Envelope): Unit = {if (system.settings.DebugAutoReceive)publish(Debug(self.path.toString, clazz(actor), "received AutoReceiveMessage " + msg))msg.message match {case t: Terminated              ⇒ receivedTerminated(t)case AddressTerminated(address) ⇒ addressTerminated(address)case Kill                       ⇒ throw ActorKilledException("Kill")case PoisonPill                 ⇒ self.stop()case sel: ActorSelectionMessage ⇒ receiveSelection(sel)case Identify(messageId)        ⇒ sender() ! ActorIdentity(messageId, Some(self))}}  

如果读者看过我之前分析的文章对上面的代码一定还有印象,它是ActorCell里面处理消息的两个函数,invoke会先判断消息类型是不是AutoReceivedMessage,如果是就自己处理了,不会去调用开发者自定义的receive函数。而Identify属于AutoReceivedMessage,收到后给sender发送了ActorIdentity消息,该消息的第二个参数是当前Actor的ActorFef变量。这样本地的actor收到远程actor返回的ActorIdentity,就可以通过对方的ActorRef给它发送消息了。当然本地actor收到的ActorIdentity消息中,第二个参数应该是一个RemoteActorRef类型。如何通过RemoteActorRef发送消息,上文已经分析清楚了,其实actorSelection最终也是通过远程actor的ActorPath创建了对应的RemoteActorRef,来发送消息的。

至此给远程actor发消息的两种方法就讲解完毕了。其实还有第三种方式,就是在本地创建一个远程Actor,当然了最终还是需要通过RemoteActorRef发消息的,这个具体就不再详细介绍了。

转载于:https://www.cnblogs.com/gabry/p/9377182.html

相关文章:

用sed 给文本文件加行号

看例子&#xff1a; [rootlocalhost tmp]# sed test.txt 1 tsttst tsttsttst 2 west gao 3 west abces [rootlocalhost tmp]# sed test.txt | sed N;s/\n/\t/ 1 tsttst tsttsttst 2 west gao 3 west abces [rootlocalhost tmp]# N的解释&#xff1a; N&am…

Qt 编译一直死循环问题

Qt 编译一直死循环问题 有时候Qt编译项目时&#xff0c; 一直编不过&#xff0c;查看一下编译窗口&#xff0c;发现一直在循环 输出如下: C:\soft\Qt5.11\5.11.1\mingw53_32\bin\qmake.exe -o Makefile ..\..\..\..\PalmQtLib\PalmQtLib\PalmQtLib.pro -spec win32-g "…

路由器运行python脚本_写个Python脚本来登录小米路由器

这个脚本写起来难度并不是很大&#xff0c;博主还是一步步的分析下&#xff0c;这样思路会比较清晰&#xff0c;下次遇到类似系统脚本写起来也更快速。好了&#xff0c;一起来分析分析。首先看下小米路由器的登录界面可以看到只需要输入密码即可登录&#xff0c;博主这里为了演…

PHP定时执行任务的实现

2019独角兽企业重金招聘Python工程师标准>>> ignore_user_abort();//关掉浏览器&#xff0c;PHP脚本也可以继续执行. set_time_limit(0);// 通过set_time_limit(0)可以让程序无限制的执行下去 $interval60*30;// 每隔半小时运行 do{//这里是你要执行的代码 sleep($i…

Spring事务管理 与 SpringAOP

1&#xff0c;Spring事务的核心接口 Spring事务管理的实现有许多细节&#xff0c;如果对整个接口框架有个大体了解会非常有利于我们理解事务&#xff0c;下面通过讲解Spring的事务接口来了解Spring实现事务的具体策略。   Spring事务管理涉及的接口的联系如下&#xff1a; 1.…

iso镜像文件烧写到U盘

iso镜像文件烧写到U盘 windows rufus-3.1.exe 百度云盘链接&#xff1a;https://pan.baidu.com/s/16p1O4lXMVTUltTvCm0DnHA 提取码&#xff1a;inzj 文件格式一般选择默认的就行,如果起不来,就换一个, linux 1、dd命令 2、系统自带 usb-creator-gtk工具 命令行输入&#x…

webgl 游戏_30个令人惊叹的WebGL示例和演示

WebGl仍在增长&#xff0c;尽管大多数现代浏览器都支持它&#xff0c;但它也可能需要在旧的浏览器上工作。在本文中&#xff0c;我遇到了很多WebGL的示例和演示&#xff0c;它们可以增进您对这项新技术的理解。因此&#xff0c;请坐下来放松身心&#xff0c;使用最新的浏览器&a…

IE8下的VML显示问题解决方案

最近在维护一个使用VML画曲线的网站&#xff0c;在不同的IE下浏览效果不一样&#xff0c;特别是在IE8下&#xff0c;出现莫名其妙的样式显示问题&#xff1a; 1.曲线不可见&#xff01;在IE9或IE7下&#xff0c;曲线正常绘制&#xff0c;但是在IE8下&#xff0c;不见坐标轴和曲…

创新工场有哪些失败项目?不要只看着成功

创新工场有哪些失败项目&#xff1f;不要只看着成功 李开复 &#xff0c;创新工场CEO回答&#xff1a;失败或碰到挑战的项目也不少。这里不点名&#xff0c;不谈细节&#xff0c;但是谈谈碰到什么挑战&#xff08;有些已经失败&#xff0c;有些还在努力&#xff09;&#xff1a…

彻底解决Linux索引节点(inode)占用率高的告警

今天邮箱里发现有一封某服务器inode使用率发生告警的邮件 登录到服务器上df -i查看&#xff0c;发现/路径下91%&#xff0c;磁盘使用率却不高&#xff0c;猜测可能是某个目录下的小文件过多&#xff0c;进而造成inode占用率过高&#xff0c;但不清楚根路径下各文件夹里的文件数…

镜像打包工具clonezilla

镜像打包工具clonezilla clonezilla 百度云盘链接&#xff1a;https://pan.baidu.com/s/1LOEPqNE9O0Z4QJmNExlgeA 提取码&#xff1a;zlso 使用方法&#xff1a; 1、将镜像直接烧入U盘 2、U盘启动

python数据分析设置_Python 数据分析系列之如何安装和设置 Python

由于人们用 Python 所做的事情不同&#xff0c;所以没有一个普适的 Python 及其插件包的安装方案&#xff0c;接下来我将详细介绍各个操作系统上 Python 科学计算环境部署。我推荐免费的 Anaconda 安装包&#xff0c;Anaconda 提供 Python 2.7 和 3.6 两个版本&#xff0c;以后…

javamail gmail

http://www.programfan.com/club/showpost.asp?id27614转载于:https://www.cnblogs.com/yqskj/archive/2013/01/11/2855715.html

robots.txt文件的解析及过滤

什么是robots.txt文件? robots.txt&#xff08;统一小写&#xff09;是一种存放于网站根目录下的ASCII编码的文本文件&#xff0c;它通常告诉网络搜索引擎的漫游器&#xff08;又称网络蜘蛛&#xff09;&#xff0c;此网站中的哪些内容是不能被搜索引擎的漫游器获取的&#xf…

CF949C Data Center Maintenance(建图+强联通分量)

题意 有 n 个信息中心&#xff0c;第 i 个信息中心要在第 ti 个小时维护&#xff0c;维护期间信息不能被获得。 每个用户的数据都有两份备份&#xff0c;第 i 个用户的数据放在信息中心 c(i,1) 和 c(i,2)。 现在要挑选一个尽量小的信息中心集合&#xff0c;使得将这个集合的维护…

fabric 启动peer_编写 Fabric 链码的一般准则

我相信智能合约(链码)是 Hyperledger Fabric 区块链网络的核心。正确开发链码可以真正发挥一个安全区块链的优势&#xff0c;反之则会带来灾难性的后果。在这篇文章里我不打算探讨 Hyperledger Fabric 链码设计的特定模式的好与坏&#xff0c;而是希望分享我在开发若干 Hyperle…

Qt pro文件下跨平台宏的使用(windows/linux 以及x86 和 arm的区分)

#Qt pro文件下跨平台宏的使用&#xff08;windows/linux 以及x86 和 arm的区分&#xff09; 在pro文件中添加&#xff1a; #仅在linux 系统下&#xff0c; 硬件平台无关的内容 unix{HEADERS \SOURCES \Manager.cpp \ }#arm64 的编译宏 contains(QMAKE_HOST.arch, aarch64){…

数论(一)——素数,GCD,LCM

这是一个数论系列&#xff1a;&#xff09; 一、素数 费马小定理 Theorem&#xff1a; 设 p 是一个素数,a 是一个整数且不是 p 的倍数,那么 很遗憾,费马小定理的逆定理是不成立的。对 a 2,满足的非素数 n 是存在的。 比如 n 341 11 31 对于整数 a,称满足的合数为以 a 为底的…

java自学 day1

1.数据类型 基本数据类型&#xff08;存放数据本身&#xff09; 分为数值型&#xff08;int&#xff0c;double等&#xff09; 字符型&#xff08;char&#xff09;布尔型&#xff08;boolean&#xff09; 引用数据类型&#xff08;存放数据的地址&#xff09;分为类&#xff0…

Qt下一行代码就可以使用的稳定易用的日志log类

Qt下一行代码就可以使用的稳定易用的日志类 此日志类是基于Qt 自带的 扩展的一个易用的日志类&#xff0c; 使用的是Qt自带的日志输出形式&#xff0c; 已长期运行在许多实际项目中&#xff0c;稳定可靠&#xff0c;而且跨平台&#xff0c; 在windows和linux 上都能稳定运行 …

apue读书笔记-第十二章

1 可重入&#xff0c;线程安全&#xff0c;异步信号安全之间的区别&#xff1f; 可重入&#xff1a;可以重复进入&#xff0c;不会引起问题&#xff08;这个概念最宽&#xff09; 线程安全&#xff1a;被多个线程使用时&#xff0c;不会出问题&#xff0c;也就是可以被多个进程…

取出url中的字符_如何在JavaScript中解析URL:例如主机名,路径名,查询,哈希?...

统一资源定位符&#xff08;缩写URL&#xff09;是对Web资源&#xff08;网页&#xff0c;图像&#xff0c;文件&#xff09;的引用。URL指定资源位置和检索资源的机制&#xff08;http&#xff0c;ftp&#xff0c;mailto&#xff09;。例如&#xff0c;这是此博客文章的URL&am…

SQL Server 2008中的Pivot和UnPivot

SQL Server 2008中SQL应用系列--目录索引 今天给新成员讲解PIVOT 和 UNPIVOT示例&#xff0c;顺便整理了一下其用法。这是自SQL Server 2005起提供的新功能。 官方示例&#xff1a;http://msdn.microsoft.com/zh-cn/library/ms177410%28vsql.105%29.aspx 首先看PIVOT示例&#…

leetcode python 032 识别最长合法括号

# 给定一个只包含字符&#xff08;和&#xff09;的字符串&#xff0c;# 找到最长的有效&#xff08;格式良好&#xff09;括号子字符串的长度。# 对于“&#xff08;&#xff08;&#xff09;”&#xff0c;最长的有效括号子串是“&#xff08;&#xff09;”&#xff0c;其长…

Android窗口管理服务WindowManagerService计算Activity窗口大小的过程分析

在Android系统中&#xff0c;Activity窗口的大小是由WindowManagerService服务来计算的。WindowManagerService服务会根据屏幕及其装饰区的大小来决定Activity窗口的大小。一个Activity窗口只有知道自己的大小之后&#xff0c;才能对它里面的UI元素进行测量、布局以及绘制。本文…

pcl需要注意的编译问题

pcl需要注意的编译问题 不要在头文件里 using namespace pcl 这会导致编译错误,而且根本分析不到错误在哪 不要在编译选项 里加 -marchnative 这个是让编译器根据你当前的cpu类型进行特定的编译优化, 例如 set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdc11 -march…

linux python版本_linux下更新Python版本并修改默认版本

linux下更新Python版本并修改默认版本&#xff0c;有需要的朋友可以参考下。很多情况下拿到的服务器python版本很低&#xff0c;需要自己动手更改默认python版本1、从官网下载python安装包(这个版本可以是任意版本3.3 2.7 2.6等等)wget http://python.org/ftp/python/2.7/Pytho…

基于HTML5的Google水下搜索

这次愚人节的时候&#xff0c;Google推出了水下搜索&#xff0c;当然&#xff0c;这只是一个愚人的小把戏&#xff0c;不过效果非常不错&#xff0c;进入页面后&#xff0c;第一眼是一个水面的效果&#xff0c;水下的鲨鱼在游来游去&#xff0c;然后Google logo和搜索框从水面上…

windows下rpc框架thrift的环境配置

windows下rpc框架thrift的环境配置 引用链接: https://www.cnblogs.com/49er/p/7193829.html 最近在弄windows下 的Facebook的rpc 框架 thrift , 网上东西看了很多, 但是大都不能一篇到位, 这里总结了一下, 也记一下自己遇到的问题和解决的方法 这里把我在实际过程中遇见的问…

CentOS 6.3 安装 samba 共享

PHP环境在linux下&#xff0c;但是开发的时候用的是windows&#xff0c;于是我用了samba将linux的一个目录共享&#xff0c;然后在windows上做映射&#xff0c;这样就可以直接在windows下编辑linux上的文件了 首先&#xff0c;安装samba软件&#xff0c;我采用的是yum安装&…