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

TensorFlow入门

为什么80%的码农都做不了架构师?>>>   hot3.png

  • TensorFlow核心教程
    • 导入TensorFlow
    • 计算图
  • tf.train API
    • 完成程序
  • tf.contrib.learn
    • 基本用法
    • 自定义模型
  • 下一步

原文链接 : https://www.tensorflow.org/get_started/get_started

译文链接 : http://www.apache.wiki/pages/viewpage.action?pageId=10029377

贡献者 : 片刻 ApacheCN Apache中文网

本指南可让您在TensorFlow中进行编程。使用本指南之前, 请安装TensorFlow。为了充分利用本指南,您应该了解以下内容:

  • 如何用Python编程
  • 至少有点数组。
  • 理想的是关于机器学习的东西。但是,如果您对机器学习知之甚少,那么这仍然是您应该阅读的第一个指南。

TensorFlow提供多种API。最低级API - TensorFlow Core - 为您提供完整的编程控制。我们推荐用于机器学习研究人员和需要对其模型进行良好控制的其他人的TensorFlow Core。更高级别的API构建在TensorFlow Core之上。这些更高级别的API通常比TensorFlow Core更容易学习和使用。此外,较高级别的API使重复任务在不同用户之间更容易,更一致。像tf.contrib.learn这样的高级API可以帮助您管理数据集,估计器,培训和推理。请注意,一些高级TensorFlow API(方法名称包含的那些)contrib仍在开发中。某些contrib方法可能会在随后的TensorFlow版本中发生变化或变得过时。

本指南从TensorFlow Core教程开始。稍后我们演示如何在tf.contrib.learn中实现相同的模型。了解TensorFlow核心原则将为您提供一个伟大的心理模型,以便您在使用更紧凑的更高级别的API时内部工作。

张量

TensorFlow中的中心数据单位是张量。张量由一组成形为任意数量的数组的原始值组成。张量的等级是其维数。以下是张量的一些例子:

3 # a rank 0 tensor; this is a scalar with shape []

[1. ,2.3.# a rank 1 tensor; this is a vector with shape [3]

[[1.2.3.], [4.5.6.]] # a rank 2 tensor; a matrix with shape [2, 3]

[[[1.2.3.]], [[7.8.9.]]] # a rank 3 tensor with shape [2, 1, 3]

TensorFlow核心教程

导入TensorFlow

TensorFlow程序的规范导入声明如下:

import tensorflow as tf

这使Python可以访问TensorFlow的所有类,方法和符号。大多数文档假定您已经完成了。

计算图

您可能会认为TensorFlow Core程序由两个独立部分组成:

  1. 构建计算图。
  2. 运行计算图。

计算图形是一系列排列成节点的图形TensorFlow操作。我们来构建一个简单的计算图。每个节点采用零个或多个张量作为输入,并产生张量作为输出。一种类型的节点是一个常数。像所有TensorFlow常数一样,它不需要任何输入,它输出一个内部存储的值。我们可以创建两个浮点式传感器node1 ,node2如下所示:

node1 = tf.constant(3.0, tf.float32)

node2 = tf.constant(4.0# also tf.float32 implicitly

print(node1, node2)

最终的打印声明生成

Tensor("Const:0", shape=(), dtype=float32) Tensor("Const_1:0", shape=(), dtype=float32)

请注意,打印节点不会输出值3.04.0正如您所期望的那样。相反,它们是在评估时分别产生3.0和4.0的节点。要实际评估节点,我们必须在会话中运行计算图。会话封装了TensorFlow运行时的控制和状态。

下面的代码创建一个Session对象,然后调用其run方法运行足够的计算图来评价node1node2。通过在会话中运行计算图如下:

sess = tf.Session()

print(sess.run([node1, node2]))

我们看到3.0和4.0的预期值:

[3.04.0]

我们可以通过将Tensor节点与操作相结合来构建更复杂的计算(操作也是节点)。例如,我们可以添加我们的两个常量节点并生成一个新的图,如下所示:

node3 = tf.add(node1, node2)

print("node3: ", node3)

print("sess.run(node3): ",sess.run(node3))

最后两个print语句生成

node3:  Tensor("Add_2:0", shape=(), dtype=float32)

sess.run(node3):  7.0

TensorFlow提供了一个名为TensorBoard的实用程序,可以显示计算图的图片。这是一个屏幕截图,显示TensorBoard如何可视化图形:

image2017-6-6%2012%3A13%3A21.png?version=1&modificationDate=1496722399000&api=v2

就这样,这个图并不是特别有趣,因为它总是产生一个恒定的结果。可以将图形参数化为接受外部输入,称为占位符。一个占位符是一个承诺后提供一个值。

= tf.placeholder(tf.float32)

= tf.placeholder(tf.float32)

adder_node = + b  # + provides a shortcut for tf.add(a, b)

前面的三行有点像一个函数或一个lambda,其中我们定义了两个输入参数(a和b),然后对它们进行一个操作。我们可以使用feed_dict参数来指定多个输入的图表来指定为这些占位符提供具体值的Tensors:

print(sess.run(adder_node, {a: 3, b:4.5}))

print(sess.run(adder_node, {a: [1,3], b: [24]}))

导致输出

7.5

3.  7.]

在TensorBoard中,图形如下所示:

image2017-6-6%2012%3A14%3A41.png?version=1&modificationDate=1496722480000&api=v2

我们可以通过添加另一个操作来使计算图更加复杂。例如,

add_and_triple = adder_node * 3.

print(sess.run(add_and_triple, {a: 3, b:4.5}))

产生输出

22.5

前面的计算图在TensorBoard中将如下所示:

image2017-6-6%2012%3A15%3A13.png?version=1&modificationDate=1496722512000&api=v2

在机器学习中,我们通常会想要一个可以接受任意输入的模型,比如上面的一个。为了使模型可训练,我们需要能够修改图形以获得具有相同输入的新输出。 变量允许我们向图中添加可训练的参数。它们的构造类型和初始值:

= tf.Variable([.3], tf.float32)

= tf.Variable([-.3], tf.float32)

= tf.placeholder(tf.float32)

linear_model = * + b

常数被调用时初始化tf.constant,其值永远不会改变。相比之下,调用时,变量不会被初始化tf.Variable。要初始化TensorFlow程序中的所有变量,必须显式调用特殊操作,如下所示:

init = tf.global_variables_initializer()

sess.run(init)

重要的是实现initTensorFlow子图的一个句柄,初始化所有的全局变量。在我们调用之前sess.run,变量未初始化。

既然x是占位符,我们可以同时评估linear_model几个值, x如下所示:

print(sess.run(linear_model, {x:[1,2,3,4]}))

产生输出

0.          0.30000001  0.60000002  0.90000004]

我们创建了一个模型,但是我们不知道它有多好。为了评估培训数据的模型,我们需要一个y占位符来提供所需的值,我们需要编写一个损失函数。

损失函数测量当前模型与提供的数据之间的距离。我们将使用线性回归的标准损失模型,其将当前模型和提供的数据之间的三角形的平方相加。linear_model - y创建一个向量,其中每个元素都是对应的示例的错误增量。我们打电话tf.square给这个错误。然后,我们求和所有平方误差,创建一个单一的标量,使用tf.reduce_sum以下方法抽象出所有示例的错误:

= tf.placeholder(tf.float32)

squared_deltas = tf.square(linear_model - y)

loss = tf.reduce_sum(squared_deltas)

print(sess.run(loss, {x:[1,2,3,4], y:[0,-1,-2,-3]}))

产生损失值

23.66

我们可以手动重新分配的值提高这Wb为-1和1变量的值,完美初始化为提供的价值 tf.Variable,但可以使用操作等来改变tf.assign。例如, W=-1并且b=1是我们的模型的最佳参数。我们可以改变W,并 b因此:

fixW = tf.assign(W, [-1.])

fixb = tf.assign(b, [1.])

sess.run([fixW, fixb])

print(sess.run(loss, {x:[1,2,3,4], y:[0,-1,-2,-3]}))

最终打印显示现在的损失为零。

0.0

我们猜测的“完美”的价值观Wb,但机器学习的整点自动找到正确的模型参数。我们将在下一节中展示如何完成此项工作。

tf.train API

机器学习的完整讨论超出了本教程的范围。然而,TensorFlow提供了优化器,缓慢地更改每个变量,以便最大程度地减少损失函数。最简单的优化器是梯度下降。它根据相对于该变量的损失导数的大小修改每个变量。通常,手动计算符号导数是乏味且容易出错的。因此,TensorFlow可以使用该函数自动生成仅给出模型描述的导数tf.gradients。为了简单起见,优化器通常为您做这个。例如,

optimizer = tf.train.GradientDescentOptimizer(0.01)

train = optimizer.minimize(loss)

sess.run(init) # reset values to incorrect defaults.

for in range(1000):

  sess.run(train, {x:[1,2,3,4], y:[0,-1,-2,-3]})

print(sess.run([W, b]))

导致最终的模型参数:

 [array([-0.9999969], dtype=float32), array([ 0.99999082], dtype=float32)]

现在我们已经完成了实际的机器学习!虽然这样做简单的线性回归并不需要太多的TensorFlow核心代码,但更复杂的模型和方法将数据输入到模型中需要更多的代码。因此,TensorFlow为常见的模式,结构和功能提供了更高级别的抽象。我们将在下一节中学习如何使用其中的一些抽象。

完成程序

完成的可训练线性回归模型如下所示:

import numpy as np

import tensorflow as tf

# Model parameters

= tf.Variable([.3], tf.float32)

= tf.Variable([-.3], tf.float32)

# Model input and output

= tf.placeholder(tf.float32)

linear_model = * + b

= tf.placeholder(tf.float32)

# loss

loss = tf.reduce_sum(tf.square(linear_model - y)) # sum of the squares

# optimizer

optimizer = tf.train.GradientDescentOptimizer(0.01)

train = optimizer.minimize(loss)

# training data

x_train = [1,2,3,4]

y_train = [0,-1,-2,-3]

# training loop

init = tf.global_variables_initializer()

sess = tf.Session()

sess.run(init) # reset values to wrong

for in range(1000):

  sess.run(train, {x:x_train, y:y_train})

# evaluate training accuracy

curr_W, curr_b, curr_loss  = sess.run([W, b, loss], {x:x_train, y:y_train})

print("W: %s b: %s loss: %s"%(curr_W, curr_b, curr_loss))

运行时,它会产生

W: [-0.9999969] b: [ 0.99999082] loss: 5.69997e-11

这个更复杂的程序仍然可以在TensorBoard中可视化 

image2017-6-6%2012%3A28%3A33.png?version=1&modificationDate=1496723311000&api=v2

tf.contrib.learn

tf.contrib.learn 是一个高级TensorFlow库,简化了机器学习的机制,其中包括:

  • 运行训练循环
  • 运行评估循环
  • 管理数据集
  • 管理喂养

tf.contrib.learn定义了许多常见的模型。

基本用法

注意线性回归程序变得简单得多 tf.contrib.learn

import tensorflow as tf

# NumPy is often used to load, manipulate and preprocess data.

import numpy as np

# Declare list of features. We only have one real-valued feature. There are many

# other types of columns that are more complicated and useful.

features = [tf.contrib.layers.real_valued_column("x", dimension=1)]

# An estimator is the front end to invoke training (fitting) and evaluation

# (inference). There are many predefined types like linear regression,

# logistic regression, linear classification, logistic classification, and

# many neural network classifiers and regressors. The following code

# provides an estimator that does linear regression.

estimator = tf.contrib.learn.LinearRegressor(feature_columns=features)

# TensorFlow provides many helper methods to read and set up data sets.

# Here we use `numpy_input_fn`. We have to tell the function how many batches

# of data (num_epochs) we want and how big each batch should be.

= np.array([1.2.3.4.])

= np.array([0.-1.-2.-3.])

input_fn = tf.contrib.learn.io.numpy_input_fn({"x":x}, y, batch_size=4,

                                              num_epochs=1000)

# We can invoke 1000 training steps by invoking the `fit` method and passing the

# training data set.

estimator.fit(input_fn=input_fn, steps=1000)

# Here we evaluate how well our model did. In a real example, we would want

# to use a separate validation and testing data set to avoid overfitting.

print(estimator.evaluate(input_fn=input_fn))

运行时,它会产生

{'global_step'1000'loss'1.9650059e-11}

自定义模型

tf.contrib.learn不会锁定您的预定义模型。假设我们想创建一个没有内置到TensorFlow中的自定义模型。我们仍然可以保留数据集,饲养,培训等的高层抽象 tf.contrib.learn。为了说明,我们将展示如何实现我们自己的等效模型,以LinearRegressor使用我们对较低级别TensorFlow API的了解。

要定义一个适合的自定义模型tf.contrib.learn,我们需要使用 tf.contrib.learn.Estimatortf.contrib.learn.LinearRegressor实际上是一个子类tf.contrib.learn.EstimatorEstimator我们只是提供Estimator一个功能model_fn来告诉 tf.contrib.learn它如何评估预测,训练步骤和损失,而不是分类 。代码如下:

import numpy as np

import tensorflow as tf

# Declare list of features, we only have one real-valued feature

def model(features, labels, mode):

  # Build a linear model and predict values

  = tf.get_variable("W", [1], dtype=tf.float64)

  = tf.get_variable("b", [1], dtype=tf.float64)

  = W*features['x'+ b

  # Loss sub-graph

  loss = tf.reduce_sum(tf.square(y - labels))

  # Training sub-graph

  global_step = tf.train.get_global_step()

  optimizer = tf.train.GradientDescentOptimizer(0.01)

  train = tf.group(optimizer.minimize(loss),

                   tf.assign_add(global_step, 1))

  # ModelFnOps connects subgraphs we built to the

  # appropriate functionality.

  return tf.contrib.learn.ModelFnOps(

      mode=mode, predictions=y,

      loss=loss,

      train_op=train)

estimator = tf.contrib.learn.Estimator(model_fn=model)

# define our data set

= np.array([1.2.3.4.])

= np.array([0.-1.-2.-3.])

input_fn = tf.contrib.learn.io.numpy_input_fn({"x": x}, y, 4, num_epochs=1000)

# train

estimator.fit(input_fn=input_fn, steps=1000)

# evaluate our model

print(estimator.evaluate(input_fn=input_fn, steps=10)) 

运行时,它会产生

{'loss'5.9819476e-11'global_step'1000}

请注意,自定义model()函数的内容与下一级API的手动模型训练循环非常相似。

下一步

现在您已经了解了TensorFlow的基础知识。我们还有更多的教程,您可以查看以了解更多。如果您是机器学习的初学者,请参阅MNIST的初学者,否则请查看深入MNIST的专家。

转载于:https://my.oschina.net/repine/blog/917955

相关文章:

C#实现类似qq的屏幕截图程序

因为近来想写个类似于远程桌面监控的程序,该程序中要用到屏幕捕捉.为实现该程序的一部分功能,做了个小DEMO.程序很简单,用到的技术也不多,只能实现类似qq的截图功能(方法虽然很笨) 程序流程如下:1.截取整个屏幕并保存 2.新开一个全屏窗口,将保…

构建RESTful风格的WCF服务

RESTful Wcf是一种基于Http协议的服务架构风格。 相较 WCF、WebService 使用 SOAP、WSDL、WS-* 而言,几乎所有的语言和网络平台都支持 HTTP 请求。 RESTful的几点好处: 1、简单的数据通讯方式,基于HTTP协议。避免了使用复杂的数据通讯方式。 …

又一起“删库”:链家程序员怒删公司 9TB 数据,被判 7 年

整理 | 王晓曼来源 | CSDN(ID:CSDNnews)1月6日,北京市第一中级人民法院公布前链家员工破坏计算机信息系统罪一案的刑事裁定书,被告人因不满工作调整,删公司9TB数据。北京市海淀区人民法院判决认定&#xff…

hbase以mr导数据方式

./hbase org.apache.hadoop.hbase.mapreduce.ImportTsv -Dimporttsv.separator"," -Dimporttsv.columnsHBASE_ROW_KEY,f1:name,f1:age,f1:addr t1 /zldata/demo1.csv转载于:https://www.cnblogs.com/sajia/p/6972420.html

Php中正则小结(一)

一.概念 语法模式类似perl.表达式必须用分隔符闭合,比如一个正斜杠(/). 分隔符可以是任意非字母非数字,除反斜杠(\)和空字节之外的非空白ascii字符 如果分隔符 在表达式中使用,需要使用反斜线进行转义。 二.组成 元字符 一个正则表达式基本组…

在C#.net中如何操作XML

在C#.net中如何操作XML需要添加的命名空间:using System.Xml; 定义几个公共对象:XmlDocument xmldoc ;XmlNode xmlnode ;XmlElement xmlelem ; 1,创建到服务器同名目录下的xml文件: 方法一:xmldoc new XmlDocument…

精彩碰撞!神经网络和传统滤波竟有这火花?

作者 | 凌霄出品 | AI大本营(ID:rgznai100)惯性传感器在航空航天系统中主要用于姿态控制和导航。微机电系统的进步促进了微型惯性传感器的发展,该装置进入了许多新的应用领域,从无人驾驶飞机到人体运动跟踪。在捷联式 …

软考新思维--2017年上半年信息系统项目管理师上午试题分析与答案(试题16-20题)...

2017年上半年信息系统项目管理师上午试题分析与答案(试题16-20题) 16.信息系统的安全威胁分成七类,其中不包括()A、自然事件风险和人为事件风险B、软件系统风险和软件过程风险C、项目管理风险和应用风险D、功能风险和效…

ASP.NET 2.0 读取配置文件[INI](示例代码下载)

(一). 功能 操作配置文件[*.ini]类 (二). 代码 1. 核心类文件 INIFILE.cs 代码 1 ///<summary>2 ///INIFILE 操作类3 ///</summary>4 publicclassINIFILE5 {6 [DllImport("kernel32")]7 privatestaticexternlongWritePrivateProfileString(stringsectio…

CSDN送会员?免费的!都来领!

距离春节还有不到一个月你准备好给家人的春节礼物了吗&#xff1f;疫情下&#xff0c;为了让程序猿同学开心加班小编提前准备了一份牛年大礼 周五福利日&#xff0c;人人都可免费领会员&#xff01;助你提前实现CSDN会员卡自由&#xff01;奖品多多&#xff0c;不仅有CSDN月卡会…

BGP相邻体之间磋商的过程

一.BGP的几个概念 空闲&#xff08;IDLE&#xff09; 等待由管理员发起的START事件 正确&#xff0c;到连接状态 错误&#xff0c;回到空闲状态 连接状态&#xff08;Connect&#xff09; 等待TCP的连接是否成功&#xff0c;以期望获得一个对等体 正确&#xff0c;到开放发送Op…

去除ios input部分默认样式

input[typesubmit],input[typebutton]{-webkit-appearance:none;outline:none } input{border-radius: 0;}转载于:https://www.cnblogs.com/bbqwwb/p/6993064.html

Asp.net 2.0 C#实现压缩/解压功能

Asp.net 2.0 C#实现压缩/解压功能 (示例代码下载) (一). 实现功能对文件及目录的压缩及解压功能(二). 运行图片示例(三).代码 1. 压缩类 1/**//// <summary> 2/// 压缩类 3/// </summary>4publicclassZipClass5{ 6 public static void ZipFile(string Fi…

图像处理工具包ImagXpress的多页TIFF编辑API的使用(1)

2019独角兽企业重金招聘Python工程师标准>>> 在ImagXpress中用用于处理TIFF文件的TIFF编辑API&#xff0c;但是怎么使用呢&#xff0c;下面来具体的看看 ImagXpress中的ImageX.DeletePage 方法一次可以删除一个页面&#xff0c;ImageX.DeletePages 方法允许开发人员…

用Matplotlib轻松复刻分析图,看看哪个城市买房最自由

作者 | 费弗里来源 | Python大数据分析简介前不久「贝壳研究院」基于其丰富的房地产相关数据资源&#xff0c;发布了「2020 新一线城市居住报告」&#xff1a;图1而在这个报告中有几张数据可视化作品还是比较可圈可点的&#xff0c;作为&#xff08;在模仿中精进数据可视化&…

Python 代码规范

前言 Python 学习之旅&#xff0c;先来看看 Python 的代码规范&#xff0c;让自己先有个意识&#xff0c;而且在往后的学习中慢慢养成习惯 目录 Python代码规范一、简明概述 1、编码 如无特殊情况, 文件一律使用 UTF-8 编码如无特殊情况, 文件头部必须加入#-*-coding:utf-8-*-标…

二级域名用asp.net 2.0的实现方案

本人所了解有两种方案&#xff0c;可能还有其的方式&#xff0c;希望大家多多讨论&#xff01; 基本思路&#xff1a;1. 域名支持泛解析&#xff0c;即是指&#xff1a;把A记录 *.域名.com 解析到服务器IP&#xff0c;服务器IIS中做绑定&#xff0c;绑定时主机头为空;2. 为了…

又一例“监视员工?”百度回应:和 996 无关,目前没有任何应用

整理 | 王晓曼图源 | 视觉中国出品 | 程序人生 &#xff08;ID&#xff1a;coder _life&#xff09;1月13日晚间&#xff0c;针对百度公开“员工工作状态预测”专利惹争议一事&#xff0c;百度在官方微博火速回应称&#xff0c;这是一个管理上的“人岗匹配”衡量方法&#xff0…

僵死进程和僵尸进程

一个进程在调用exit命令结束自己的生命的时候&#xff0c;其实它并没有真正的被销毁&#xff0c;而是留下一个称为僵尸进程&#xff08;Zombie&#xff09;的数据结构&#xff08;系统调用exit&#xff0c;它的作用是使进程退出&#xff0c;但也仅仅限于将一个正常的进程变成一…

AC日记——[HNOI2010]BOUNCE 弹飞绵羊 洛谷 P3203

[HNOI2010]BOUNCE 弹飞绵羊 思路&#xff1a; SBlct&#xff1b; 代码&#xff1a; #include <bits/stdc.h> using namespace std; #define maxn 200005 int n,m,f[maxn],ch[maxn][2],rev[maxn],ki[maxn],sta[maxn],top,lit,size[maxn]; inline void in(int &now) {c…

C#与RSS亲密接触

讲述动态生成RSS文件的方法。动态生成RSS文件也基本有两种方法&#xff0c;一种是用字符串累加的方法&#xff0c;另一种是使用xml文档生成的方法。字符串累加的方法也比较简单&#xff0c;我也就不多说了&#xff0c;这里着重说一下生成XmlDocument的方法&#xff0c;包括各种…

2020 ACM Fellows 名单出炉,13 名华人入选,7 名来自国内!

【编者按】一年一度的 ACM Fellow 名单现已新鲜出炉&#xff01;向来以严格审查闻名的ACM Fellows&#xff0c;今年居然共选择了 95 名科学家&#xff0c;其中还有 13 位华人&#xff0c;来看看都是哪些大佬吧&#xff01;整理 | 郑丽媛出品 | CSDN&#xff08;ID&#xff1a;C…

Mybatis调用Oracle的存储过程

如何使用Mybaits调用数据库中的存储过程&#xff0c;下面以Oracle数据库的为例&#xff1a;1&#xff0e;在数据库中创建以下的存储过程&#xff1a;2&#xff0e;编写SQL映射文件WxclDAO.xml&#xff1a;<select id"selectWxcl2" parameterType"java.util.M…

JavaScript - 数据类型和变量

计算机顾名思义就是可以做数学计算的机器&#xff0c;因此&#xff0c;计算机程序理所当然地可以处理各种数值。但是&#xff0c;计算机能处理的远不止数值&#xff0c;还可以处理文本、图形、音频、视频、网页等各种各样的数据&#xff0c;不同的数据&#xff0c;需要定义不同…

用Socket发邮件的代码(可以群发)

qunFa.aspx文件的代码&#xff1a; <%... Page language"c#" Codebehind"qunFa.aspx.cs" AutoEventWireup"false" Inherits"liuwei.hanmail.qunFa" %><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN&qu…

rcp(插件开发)插件B需要引用插件A中的jar包-如何处理依赖关系

如果插件B需要引用插件A中的jar 通常需要以下几步&#xff1a; 1.插件B要依赖插件A 2.在插件B的build path中添加插件A的jar包 3.插件A的runtime导出插件B中使用jar的package

微软Cortana全面升级神经网络语音,效果堪比真人发音

近日&#xff0c;微软在全球范围内对Cortana进行了神经网络语音全面升级&#xff0c;升级后的Cortana更加自然流畅&#xff0c;语音效果堪比真人发音。 以下是Cortana不同国家、不同语言升级前后语音效果对比&#xff1a; Cortana音频 此次升级利用了深度神经网络技术&#…

Spring《五》集合的注入方式

List、Set、Map、Properties 1、List <property name"msg"> <list> <value>gf</value> <value>gd</value> <value>HelloWorld</value> </list> </property> 2、Set <property name"msg"&g…

虚方法的调用是怎么实现的(单继承VS多继承)

我们知道通过一个指向之类的父类指针可以调用子类的虚方法&#xff0c;因为子类的方法会覆盖父类同样的方法&#xff0c;通过这个指针可以找到对象实例的地址&#xff0c;通过实例的地址可以找到指向对应方法表的指针&#xff0c;而通过这个方法的名字就可以确定这个方法在方法…

asp.net 2.0防止同一用户同时登陆

要防止同一用户同时登陆,首页应该记录在线用户的信息(这里与用户名为例),然后判断正在登陆的用户里面是否已存在&#xff0e;在这里使用一个cache存放已经登陆的用户名&#xff0e;但是还有一个问题就是要知道用户是什么时候离开系统的呢&#xff1f;这就要定期清除cache中的内…