精华内容
下载资源
问答
  • 近期,和合信诺与招商银行股份有限公司(简称“招行”)私人银行展开合作,建设基于自然语言处理、知识图谱、智能应答与搜索引擎等技术的智能合规知识引擎项目,全力支持招商银行私人银行业务应用升级。目前,该项目...

    近期,和合信诺与招商银行股份有限公司(简称“招行”)私人银行展开合作,建设基于自然语言处理、知识图谱、智能应答与搜索引擎等技术的智能合规知识引擎项目,全力支持招商银行私人银行业务应用升级。目前,该项目已在2019年2月份成功落地。

    智能合规成为银行业务扩张基石

    作为国内首批开展私人银行业务的领军者,招行私人银行自2007年成立以来,始终秉持“助您家业常青,是我们的份内事”的经营理念,坚持以打造投资顾问服务为核心竞争优势的差异化竞争策略,持续完善和丰富开放式产品平台,致力于为高净值客户个人、家族和企业在投资、税务、法务、并购、融资等方面的多元化需求提供综合服务。

    经过11年的快速发展,招行私人银行已经形成了良好的品牌影响力。目前,招行私人银行已发展到44家分行,管理客户资产规模 (AUM)超过2万亿大关,稳坐国内商业银行私行领域的第一宝座。在商业银行普遍加码大零售转型的眼下,招行继续在零售业务中最高端的领地——私人银行业务一骑绝尘。

    私人银行业务近十年的高速发展也是处在我国金融行业发展最快的时期,尤其表现为金融行业增加值在GDP的比重逐渐攀升。不过,金融体系在发展过程中也出现了一些问题,比如链条日益复杂,一些所谓“创新”逐渐脱离实体、沦为纯粹的监管套利等。2016年中央经济工作会议提出,要把防控金融风险放到更加重要的位置,着力防控资产泡沫,提高和改进监管能力,确保不发生系统性金融风险,开启了本轮金融严监管的大潮。

    在监管日益趋严的大背景下,各类政策文档越来越多,银行合规人员和一线业务人员面临了巨大挑战:合规人员面对大量解读和管理政策文档的工作;一线业务人员需要大量合规人员帮助其及时理解最新金融政策要求。金融机构希望可以透过新型监管科技 (RegTech)帮助其迎接挑战,改变传统的文档管理模式、人工咨询方式,通过更加数字化、体系化、智能化的技术方案,减少日益增加的银行运营成本,提高银行业务效率。

    因此,为进一步完善客户体验,更好的开展业务,招行私人银行采用人工智能、大数据、云计算等新兴技术推出了一系列创新举措。此次招行私人银行牵手和合信诺,构建智能合规知识引擎是其涉足监管科技领域的第一步,并将极大助力其业务实现转型升级。

    携手和合信诺,打造智能合规引擎项目


    和合信诺依托超过10年的监管合规、风险管理和金融领域的专业底蕴,同时依托多年深耕行业实践积累了深厚的人工智能、大数据分析、机器学习、自然语言处理等前沿技术经验。在监管科技领域,和合信诺的优势尤为突出,不仅在最短时间内打造出了智能合规知识引擎,同时多款明星产品已得到市场及客户的认可。

    此次合作中,招行私人银行采用和合信诺研发的“智能合规知识引擎”,利用人工智能、知识图谱技术将复杂专业的合规知识通过计算机系统承载,对内梳理专业合规知识体系,对外广泛用于银行一线业务人员智能问答、合规培训、交易预分析等功能。在未来,通过系统的不断迭代升级,将慢慢转变合规专家的职能。

    “智能合规知识引擎”的独到优势在于:针对招行私人银行目前现存的大量合规相关文档,提供统一的合规知识入口,减少复杂的文件管理查询时间,方便管理历史合规文件,更好地将合规知识串联;利用合规知识建立知识图谱,结合业务,梳理合规知识,实现客户交易预分析;同时,依靠合规知识图谱,实现智能的合规政策咨询,及时有效地帮助客户经理解决一线客户问题。

    为了能更准确地帮助招行私人银行快速服务前端客户经理、总行业务支持人员以及总行合规岗人员,“合规知识智能引擎”利用交互介入层、业务流程层、核心服务层、基础服务层以及底层中间层结合业务流程和交互层实现更加智能的FAQ智能问答、文档搜索以及管理端UI。该产品注入更强大的NLP和机器学习技术,运用更精准的模型算法通过知识细分拆解提高知识呈现的准确度。产品对人工做到了极大的解放,毫秒级完成搜索展示,准确度与人为判定相当,有效解决了人工查询及沟通成本。

    坚持监管合规,和合信诺助力监管科技发展

    与招行私人银行合作建设研发的智能合规知识引擎,是和合信诺推出“金融科技”下“监管科技”战略的重要体现之一,以业务引领、科技驱动的金融业务创新来协助传统银行实现金融科技转型,专注做金融科技的践行者。和合信诺主张大技术小应用,采用人工智能、大数据分析、机器学习、自然语言处理等前沿技术,结合业务需求,帮助银行搭建人工智能应用平台。

    随着强监管时代的到来,监管科技的应用将带来监管理念、手段和方式的不断升级,和合信诺将不断为招行私人银行等金融机构提供更多符合监管科技的智能合规产品,以及更深入定制化的监管合规咨询和解决方案,降低银行成本,助力传统银行实现金融科技转型。

    关于和合信诺

    和合信诺成立于2017年4月,是一家兼具银行基因和互联网基因的金融科技公司。核心团队成员毕业于英国南安普顿大学、纽约大学、厦门大学及复旦大学等国内外知名院校,曾经服务于Google、花旗银行等国际知名企业,拥有超过10年的监管合规、风险管理、金融服务领域的专业底蕴。随着强监管时代的到来,和合信诺将以监管科技为切入点,助力传统银行实现金融科技转型。目前,和合信诺已经与招商银行、平安集团等领先金融机构展开深入合作,是众多客户在金融科技领域最为信赖的合作伙伴之一。

    阅读原文:和合信诺牵手招行私人银行,构建智能合规知识引擎

    展开全文
  • 在真表中: # 1 is true and 0 is false. But you knew that already, didn't you? input | output _______________ 00 | 0 01 | 1 10 | 1 11 | 0 With more than 2 inputs, the XOR function returns the parity...

    julia 学习

    Training a multi-layer perceptron with automatic differentiation package Zygote.

    使用自动分化程序包Zygote训练多层感知器。

    学习异或 (learning to XOR)

    Hi. This is a tutorial about building a very simple multilayer perceptron to approximate the exclusive-or function, known as the XOR function to its friends. With 2 logical (i.e. true or false) inputs, XOR is returns true if only one input is true. In a truth table:

    你好 这是一个有关如何构建一个非常简单的多层感知器以逼近其异或功能(对它的朋友们称为XOR函数)的教程。 对于2个逻辑( 即,真或假)输入,如果只有一个输入为真,则XOR返回true。 在真值表中:

    # 1 is true and 0 is false. But you knew that already, didn't you?
    input | output
    _______________
    00 | 0
    01 | 1
    10 | 1
    11 | 0

    With more than 2 inputs, the XOR function returns the parity of the inputs. That is, it returns true if the total number of bits in the bitstring is odd. In this tutorial we’ll use 3 bits, chosen mainly to make the decision boundary animation at the top of this article more interesting.

    如果输入多于2个,则XOR函数将返回输入的奇偶校验。 也就是说,如果位串中的总位数为奇数,则返回true。 在本教程中,我们将使用3个位,主要是为了使本文顶部的决策边界动画更加有趣而选择了3位。

    input | output
    _______________
    000 | 0
    001 | 1
    010 | 1
    011 | 0
    100 | 1
    101 | 0
    110 | 0
    111 | 1

    This might also be your introduction to the Julia programming language, and represents some of my earliest experiments with the language. Despite the questionable choice of name (necessitating that you qualify it by adding “programming language” almost every time you say it), Julia has some notable advantages.

    这也可能是您对Julia编程语言的介绍,并且代表了我对该语言的最早实验。 尽管名称选择存在问题(几乎每次您说出来都必须通过添加“编程语言”来限定它的名称),Julia还是有一些明显的优势。

    Developed for scientific computing, the Julia language is ostensibly something of a faster Python, thanks to just-in-time compilation. One interesting feature of the language is that when you see a mathematical definition for a dense layer in a neural network, like so:

    Julia语言是为科学计算而开发的,表面上它是即时Python,这要归功于即时编译。 该语言的一个有趣特征是,当您看到神经网络中密集层的数学定义时,如下所示:

    𝑓(𝑥)=𝜎(𝜃𝑥+𝑏)

    𝑓(𝑥)= 𝜎(𝜃𝑥 +𝑏)

    You can write working code that looks very similar, thanks to Julia’s support for unicode characters. It doesn’t necessarily save you any time typing (symbols are entered by typing the Latex command, e.g. \sigma and pressing tab), but it does look pretty cool. The following is perfectly legitimate code in Julia:

    感谢Julia对Unicode字符的支持,您可以编写看起来非常相似的工作代码。 它不一定可以节省您键入的任何时间(通过键入Latex命令输入符号, 例如 \sigma并按Tab),但是它看起来确实很酷。 以下是Julia中完全合法的代码:

    σ(x) = 1 ./ (1 .+ exp.(-x))f(x, θ) = σ(x * θ[:w] .+ θ[:b])θ = Dict(:w => randn(32,2)/10, :b => randn(1,2)/100)
    x = randn(4,32)f(x, θ)

    And returns something along the lines of:

    并返回以下内容:

    4×2 Array{Float64,2}:
    0.516507 0.482128
    0.568403 0.639701
    0.571232 0.416161
    0.288268 0.546431

    If you want to

    如果你想

    或或X或 就是那个问题。 (to OR or X to OR? that is the question.)

    The exclusive-or (XOR) function is an attractive function to approximate witha simple neural network, both for its simplicity and for its somewhat notorious place in AI research history. In the 1960s a pair of mages of AI nobility proclaimed their revelation that a weighted mapping of inputs to a single output node ( a la Frank Rosenblatt’s Perceptron or the McCulloch-Pitts neuron) could not fit the XOR function, plunging the frontier into chaos and darkness for an epoch. Or so the legend goes. In retrospect it seems that some formal arguments by Minsky and Paypert were taken to be emblematic of all practical implementation. In fact they only proved that dense connections (i.e. non-local weights) and multiple layers were needed to correctly recognize the parity predicate (XOR).

    异或(XOR)函数是一种吸引人的函数,可以用简单的神经网络进行近似,这既因为其简单性,又因为它在AI研究历史中的地位臭名昭著。 1960年代,一对AI贵族法师宣告他们的启示 ,即输入到单个输出节点( la Frank Rosenblatt的Perceptron或McCulloch-Pitts神经元)的加权映射无法满足XOR功能,使边界陷入混乱,黑暗的时代。 传说就这样了。 回想起来,明斯基和佩珀特的一些正式论点似乎被视为所有实际实施的象征。 实际上,他们只证明需要密集的连接( 非本地权重)和多层才能正确识别奇偶谓词(XOR)。

    #Separating OR with a straight line is easy, your  eyes will pick out the answer automatically
    1 x x
    0 o x 0 11 \x x
    \
    \
    0 o \ x
    \
    0 1
    # Separating XOR is not so simple, you'll need a curved line to do it. 1 x \ o
    ____ \____
    |
    0 o \ x
    |
    0 1

    Since then it’s something of a tradition to program an MLP to solve the XOR problem when picking up a new language for ML.

    从那时起,为MLP编程以选择一种新语言时,对MLP进行编程以解决XOR问题是一种传统。

    自动区分和软件2.0 (automatic differentiation and software 2.0)

    We’ll use the automatic differentiation package Zygote from FluxML. If you have used Autograd or JAX before, Zygote will feel familiar, as Zygote is an autodiff package in true “Software 2.0” spirit. You can differentiate over native Julia code including loops, flow control, and recursion. This can have some pretty nifty advantages, for example you can differentiate through a physics model to improve learning for reinforcement learning style control problems. In our case we’ll just differentiate with respect to a few matrix multiplies, and if you’d rather enjoy this tutorial interactively in the form of a Jupyter notebook, visit the Gihub repo.

    我们将使用FluxML的自动差异化软件包Zygote 。 如果您以前使用过AutogradJAX ,Zygote会感到很熟悉,因为Zygote是真正的“ Software 2.0”精神下的autodiff软件包。 您可以区分本地Julia代码,包括循环,流控制和递归。 这可能具有一些非常漂亮的优点,例如,您可以通过物理模型进行区分以改善针对强化学习风格控制问题的学习 在我们的案例中,我们仅针对几个矩阵乘法进行区分,如果您希望以Jupyter笔记本的形式交互式地欣赏本教程,请访问Gihub回购

    We’ll use Zygote to automatically give us a gradient to update our NN parameters. This might look a little different if you are used to calling loss.backward() in PyTorch or explicitly programming your own backward pass. Zygote performs the forward and backward pass for us automatically. Unfortunately this meant that I had to call separate forward passes for both training metrics and gradients, but I’ll add an update here when I find a good way to avoid the redundant forward pass call.

    我们将使用Zygote自动为我们提供渐变以更新我们的NN参数。 如果您习惯于在PyTorch中调用loss.backward()显式地编程自己的向后传递,则可能看起来有些不同。 Zygote自动为我们执行前进和后退。 不幸的是,这意味着我必须为训练指标和渐变调用单独的正向传递,但是当我找到一种避免冗余正向传递的好方法时,我将在此处添加更新。

    lr = 1e1;
    x, y = get_xor(64,5);
    θ = init_weights(5);old_weights = append!(reshape(θ[:wxh],
    size(θ[:wxh])[1]*size(θ[:wxh])[2]),
    reshape(θ[:why], size(θ[:why])[1] * size(θ[:why])[2]))
    dθ = gradient((θ) -> get_loss(x, θ, y), θ);
    plt = scatter(old_weights, label = "old_weights");θ[:wxh], θ[:why] = θ[:wxh] .- lr .* dθ[1][:wxh], θ[:why] .- lr .* dθ[1][:why]new_weights = append!(reshape(θ[:wxh],
    size(θ[:wxh])[1]*size(θ[:wxh])[2]),
    reshape(θ[:why], size(θ[:why])[1] * size(θ[:why])[2]))scatter!(new_weights, label="new weights")
    display(plt)
    Image for post
    Weights modified according to their gradient.
    权重根据其梯度进行修改。

    Now to get started. First we’ll import the packages we’ll use. That’s Zygote and a few others we’ll use for plotting and calculating statistics.

    现在开始。 首先,我们将导入将使用的软件包。 这就是Zygote和我们将用于绘制和计算统计数据的其他几个。

    using Zygote
    using Stats
    using Plots
    using StatsPlots

    We’ll need both training data and some matrices to act as neural weights, which the functions below will produce for us.

    我们需要训练数据和一些矩阵来充当神经权重,下面的函数将为我们提供这些权重。

    get_xor = function(num_samples=512, dim_x=3)
    x = 1*rand(num_samples,dim_x) .> 0.5
    y = zeros(num_samples,1) for ii = 1:size(y)[1]
    y[ii] = reduce(xor, x[ii,:])
    end x = x + randn(num_samples,dim_x) / 10 return x, y
    endinit_weights = function(dim_in=2, dim_out=1, dim_hid=4)
    wxh = randn(dim_in, dim_hid) / 8
    why = randn(dim_hid, dim_out) / 4
    θ = Dict(:wxh => wxh, :why => why)
    return θ
    end

    This next bit defines the model we’ll be training: a tiny MLP with 1 hidden layer and no biases. We also need to set up a few helper functions to provide loss and other training metrics (accuracy). To use Zygote’s automatic differentiation capabilities, we need a function that returns a scalar objective function.

    接下来的一点定义了我们将要训练的模型:一个微小的MLP,具有1个隐藏层并且没有偏差。 我们还需要设置一些辅助功能来提供损失和其他训练指标(准确性)。 要使用Zygote的自动微分功能,我们需要一个返回标量目标函数的函数。

    f(x, θ) = σ(σ(x * θ[:wxh]) * θ[:why])get_accuracy(y, pred, boundary=0.5) = mean(y .== (pred .> boundary))
    log_loss = function(y, pred)
    return -(1 / size(y)[1]) .* sum(y .* log.(pred) .+ (1.0 .- y)
    .* log.(1.0 .- pred))endget_loss = function(x, θ, y, l2=6e-4)pred = f(x, θ)
    loss = log_loss(y, pred)
    loss = loss + l2 * (sum(abs.(θ[:wxh].^2))
    + sum(abs(θ[:why].^2)))
    return lossend

    The gradient function from Zygote does as the name suggests. We need to give gradient a function that returns our objective function (log loss in this case), which is why we made an explicit get_loss function earlier. We'll store the results in a dictionary called dθ, and update our model parameters by following gradient descent. The function below defines our training loop.

    顾名思义,Zygote的gradient函数可以做到。 我们需要给gradient函数一个返回目标函数的函数(在这种情况下为对数丢失),这就是为什么我们较早地get_loss了一个明确的get_loss函数的原因。 我们将结果存储在名为dθ的字典中,并通过遵循梯度下降来更新模型参数。 下面的函数定义了我们的训练循环。

    train = function(x, θ, y, max_steps=1000, lr=1e-2, l2_reg=1e-4)
    disp_every = max_steps // 100 losses = zeros(max_steps)
    acc = zeros(max_steps) for step = 1:max_steps
    pred = f(x, θ)
    loss = log_loss(y, pred)
    losses[step] = loss
    acc[step] = get_accuracy(y, pred) dθ = gradient((θ) -> get_loss(x, θ, y, l2_reg), θ) θ[:wxh], θ[:why] = θ[:wxh] .- lr
    .* dθ[1][:wxh], θ[:why] .- lr .* dθ[1][:why]
    if mod(step, disp_every) == 0
    val_x, val_y = get_xor(512, size(x)[2]);
    pred = f(val_x, θ)
    loss = log_loss(val_y, pred)
    accuracy = get_accuracy(val_y, pred) println("$step loss = $loss, accuracy = $accuracy")
    #save_frame(θ, step); end end
    return θ, losses, accend

    With all our functions defined, it’s time to set everything up and start training. We’ll use violin plots from the StatsPlots package to show how the distributions of weights change over time, using a plot function with the ! in-place modifier to add more plots to the current figure. If we want to display more than 1 figure per notebook cell, and we do, we need to explicitly call display on the figure we want to show.

    定义好所有功能后,就该进行设置并开始培训了。 我们将使用StatsPlots包中的violin图,使用带有!plot函数来显示权重的分布随时间的变化! 就地修饰符可向当前图形添加更多图。 如果我们要在每个笔记本单元格中显示多个图形,并且需要这样做,则需要在要display的图形上显式调用display

    dim_x = 3
    dim_h = 4
    dim_y = 1
    l2_reg = 1e-4
    lr = 1e-2
    max_steps = 1400000θ = init_weights(dim_x, dim_y, dim_h)
    x, y = get_xor(1024, dim_x)println(size(x))plt = violin([" "], reshape(θ[:wxh],dim_x * dim_h), label="wxh", title="Weights", alpha = 0.5)
    violin!([" "], reshape(θ[:why],dim_h*dim_y), label="why", alpha = 0.5)
    display(plt)θ, losses, acc = train(x, θ, y, max_steps, lr, l2_reg)plt = violin([" "], reshape(θ[:wxh],dim_x * dim_h), label="wxh", title="Weights", alpha = 0.5)
    violin!([" "], reshape(θ[:why],dim_h*dim_y), label="why", alpha = 0.5)
    display(plt)steps = 1:size(losses)[1]
    plt = plot(steps, losses, title="Training XOR", label="loss")
    plot!(steps, acc, label="accuracy")
    display(plt)
    Image for post
    Image for post
    Weights changing over the course of a training, learning curve shown on the right.
    权重在训练过程中变化,右侧显示学习曲线。

    Finally, it’s a good idea to generate a test set to figure how badly our model is overfitted to the training data. If you’re unlucky and get poor performance from your model, try changing some of the hyperparameters like learning rate or L2 regularization. You can also generate a larger training dataset for better performance, or try changing the size of the hidden layer by changing dim_h. Heck, you could even modify the code to add L1 regularization or add layers to the MLP, so knock your socks off and have a go.

    最后,生成一个测试集以判断我们的模型对训练数据的拟合有多严重是一个好主意。 如果您不走运,并且模型效果不佳,请尝试更改一些超参数,例如学习率或L2正则化。 您也可以生成更大的训练数据集以获得更好的性能,或者尝试通过更改dim_h来更改隐藏层的大小。 哎呀,您甚至可以修改代码以添加L1正则化或向MLP添加层,因此请脱颖而出。

    test_x, test_y = get_xor(512,3);pred = f(test_x, θ);
    test_accuracy = get_accuracy(test_y, pred);
    test_loss = log_loss(test_y, pred);println("Test loss and accuracy are $test_loss and $test_accuracy")>>Test loss and accuracy are 0.03354685023541572 and 1.0

    测试与验证 (testing vs validation)

    The difference between a test and validation dataset is blurry when we generate data on demand as we do here, but normally you wouldn’t want to go back and modify your training algorithm after running your model on a static test dataset. That sort of behavior runs a high risk of data leakage as you can keep tweaking training until you get good performance, but if stop only when the test score is good you’ll actually have settled on a lucky score. That doesn’t tell you anything about how the model will behave with actual test data that it hasn’t seen before, and this happens often in the real world when researchers collectively iterate on a few standard dataset. Of course there will be incremental improvement every year on MNIST if everyone keeps fitting their research strategy to the test set!

    当我们按照此处的方法按需生成数据时,测试数据集和验证数据集之间的差异是模糊的,但是通常您不希望在静态测试数据集上运行模型后返回并修改训练算法。 这种行为会带来数据泄露的高风险,因为您可以不断调整训练直到获得良好的性能,但是如果仅在测试成绩良好时停止,您实际上将获得一个幸运的分数。 这并没有告诉您有关该模型如何使用以前从未见过的实际测试数据运行的任何信息,而这通常发生在现实世界中,当研究人员共同迭代几个标准数据集时。 当然,如果每个人都将自己的研究策略与测试集保持一致,那么MNIST每年将得到逐步改进

    In any case, thanks for stopping by and I hope you enjoyed exploring automatic differentiation in Julia as I did.

    无论如何,感谢您的光临,我希望您像我一样喜欢在Julia中探索自动区分。

    Image for post

    翻译自: https://medium.com/sorta-sota/learning-xor-with-julia-and-zygote-16003f171ae0

    julia 学习

    展开全文
  • 这是因为List是非线程安全集合,意思就是说所有的线程都可以修改他的。 下面我们来看下并行集合 —— 线程安全集合,在System.Collections.Concurrent命名空间中,首先来看一下ConcurrentBag泛型集合,其用法和...

    合买平台搭建

    并行算法的出现,随之而产生的也就有了并行集合,及线程安全集合;微软向的也算周到,没有忘记linq,也推出了linq的并行版本,plinq - Parallel Linq.

    一、并行集合 —— 线程安全集合

      并行计算使用的多个线程同时进行计算,所以要控制每个线程对资源的访问,我们先来看一下平时常用的List<T>集合,在并行计算下的表现,新建一个控制台应用程序,添加一个PEnumerable类(当然你也直接写到main方法里面测试,建议分开写),写如下方法:

    复制代码

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Collections.Concurrent;

    namespace ThreadPool
    {
    public class PEnumerable
    {
    public static void ListWithParallel()
    {
    List<int> list = new List<int>();
    Parallel.For(0, 10000, item =>
    {
    list.Add(item);
    });
    Console.WriteLine("List's count is {0}",list.Count());
    }
    }
    }

    复制代码

    点击F5运行,得到如下结果:

    看到结果中显示的5851,但是我们循环的是10000次啊!怎么结果不对呢?这是因为List<T>是非线程安全集合,意思就是说所有的线程都可以修改他的值。

    下面我们来看下并行集合 —— 线程安全集合,在System.Collections.Concurrent命名空间中,首先来看一下ConcurrentBag<T>泛型集合,其用法和List<T>类似,先来写个方法测试一下:

    复制代码

    public static void ConcurrentBagWithPallel()
    {
    ConcurrentBag<int> list = new ConcurrentBag<int>();
    Parallel.For(0, 10000, item =>
    {
    list.Add(item);
    });
    Console.WriteLine("ConcurrentBag's count is {0}", list.Count());
    }

    复制代码

    同时执行两个方法,结果如下:

    可以看到,ConcurrentBag集合的结果是正确的。下面我们修改代码看看ConcurrentBag里面的数据到底是怎么存放的,修改代码如下:

    复制代码

    public static void ConcurrentBagWithPallel()
    {
    ConcurrentBag<int> list = new ConcurrentBag<int>();
    Parallel.For(0, 10000, item =>
    {
    list.Add(item);
    });
    Console.WriteLine("ConcurrentBag's count is {0}", list.Count());
    int n = 0;
    foreach(int i in list)
    {
    if (n > 10)
    break;
    n++;
    Console.WriteLine("Item[{0}] = {1}",n,i);
    }
    Console.WriteLine("ConcurrentBag's max item is {0}", list.Max());

      }

    复制代码

    先来看一下运行结果:

    可以看到,ConcurrentBag中的数据并不是按照顺序排列的,顺序是乱的,随机的。我们平时使用的Max、First、Last等linq方法都还有。其时分类似Enumerable的用法,大家可以参考微软的MSDN了解它的具体用法。

    关于线程安全的集合还有很多,和我们平时用的集合都差不多,比如类似Dictionary的ConcurrentDictionary,还有ConcurrentStack,ConcurrentQueue等。

    二、Parallel Linq的用法及性能

    1、AsParallel

    前面了解了并行的For和foreach,今天就来看一下Linq的并行版本是怎么样吧?为了测试,我们添加一个Custom类,代码如下:

    public class Custom
    {
    public string Name { get; set; }
    public int Age { get; set; }
    public string Address { get; set; }
    }

    写如下测试代码:

    复制代码

    public static void TestPLinq()
    {
    Stopwatch sw = new Stopwatch();
    List<Custom> customs = new List<Custom>();
    for (int i = 0; i < 2000000; i++)
    {
    customs.Add(new Custom() { Name = "Jack", Age = 21, Address = "NewYork" });
    customs.Add(new Custom() { Name = "Jime", Age = 26, Address = "China" });
    customs.Add(new Custom() { Name = "Tina", Age = 29, Address = "ShangHai" });
    customs.Add(new Custom() { Name = "Luo", Age = 30, Address = "Beijing" });
    customs.Add(new Custom() { Name = "Wang", Age = 60, Address = "Guangdong" });
    customs.Add(new Custom() { Name = "Feng", Age = 25, Address = "YunNan" });
    }

         sw.Start();
         var result = customs.Where<Custom>(c => c.Age > 26).ToList();
         sw.Stop();
         Console.WriteLine("Linq time is {0}.",sw.ElapsedMilliseconds);
    
         sw.Restart();
         sw.Start();
         var result2 = customs.AsParallel().Where<Custom>(c => c.Age > 26).ToList();
         sw.Stop();
         Console.WriteLine("Parallel Linq time is {0}.", sw.ElapsedMilliseconds);
      }

    复制代码

    其实也就是加了一个AsParallel()方法,下面来看下运行结果:

    时间相差了一倍,不过有时候不会相差这么多,要看系统当前的资源利用率。大家可以多测试一下。

    其实,AsParallel()这个方法可以应用与任何集合,包括List<T>集合,从而提高查询速度和系统性能。

    2、GroupBy方法

    在项目中,我们经常要对数据做处理,比如分组统计,我们知道在linq中也可以实现,今天来学习一下新的ToLookup方法,写一个测试方法,代码如下:

    复制代码

    public static void OrderByTest()
    {
    Stopwatch stopWatch = new Stopwatch();
    List<Custom> customs = new List<Custom>();
    for (int i = 0; i < 2000000; i++)
    {
    customs.Add(new Custom() { Name = "Jack", Age = 21, Address = "NewYork" });
    customs.Add(new Custom() { Name = "Jime", Age = 26, Address = "China" });
    customs.Add(new Custom() { Name = "Tina", Age = 29, Address = "ShangHai" });
    customs.Add(new Custom() { Name = "Luo", Age = 30, Address = "Beijing" });
    customs.Add(new Custom() { Name = "Wang", Age = 60, Address = "Guangdong" });
    customs.Add(new Custom() { Name = "Feng", Age = 25, Address = "YunNan" });
    }

         stopWatch.Restart();
         var groupByAge = customs.GroupBy(item => item.Age).ToList();
         foreach (var item in groupByAge)
         {
            Console.WriteLine("Age={0},count = {1}", item.Key, item.Count());
         }
         stopWatch.Stop();
    
         Console.WriteLine("Linq group by time is: " + stopWatch.ElapsedMilliseconds);
    
         stopWatch.Restart();
         var lookupList = customs.ToLookup(i => i.Age);
         foreach (var item in lookupList)
         {
            Console.WriteLine("LookUP:Age={0},count = {1}", item.Key, item.Count());
         }
         stopWatch.Stop();
         Console.WriteLine("LookUp group by time is: " + stopWatch.ElapsedMilliseconds);
      }

    复制代码

    运行结果如下:

    ToLookup方法是将集合转换成一个只读集合,所以在大数据量分组时性能优于List.大家可以查阅相关资料,这里由于篇幅问题,不再细说。

    转载于:https://blog.51cto.com/13890757/2151164

    展开全文
  • 不同的计算机保存和解析数据时顺序是不一致的(主机字节序),如整数1在发送方的存贮方式是这样的:00000000 00000000 00000000 00000001,如果接收方和发送方的主机字节序相反,它保存的是:00000001 00000000 ...

    以下讲的是tcp连接,client和server是tcp协议不再强调。

    心跳检测

    1,为什么需要心跳检测?

    tcp连接中,socket_listen()相当于电话处于监听状态,有N个client等待连接,socket_accept()函数相当于接听一个电话,返回一个文件描述符fd(file description),在window中叫socket句柄,代表一个客户端连接。

    $fd = socket_accept(resource $socket);
    

    fd数量是有限制的,swoole中提到最大1600W,事实真的如此吗?每个连接都要消耗内存,实际fd数量取决于内存。超过server端设置的max_connect,新进入的连接将被拒绝。所以server会对连接空间时间(idle)过长的连接主动关闭,回收fd资源,达到复用的目的。

    swoole中server的配置选项:

    $serv->set([
    	'heartbeat_idle_time'=>60, //客户端最大连接空间时间
    	'heartbeat_check_interval'=>5, //每5秒服务端主动检测客户端连接的空闲时间
    	]);
    

    idle代表客户端连接空间时间,在redis 127.0.0.1:6379>client list中,打印的client信息中就包含idle参数,没错,redis也是这么回收连接资源的。

    2,实现保持连接
    如client想一直保持连接,则需定时向server发送数据,以免被server主动关闭连接。心跳的另个作用是检测连接是否正常,如三次server未响应,则发起重连。

    实现很简单,client端只要一个定时器定时发送数据就可以了。

    /**
    * Client
    */
    swoole_timer_tick(9000,function () use($client){
         $client->send('1');
    });
    

    尽量用较小的数据减少宽带消耗。

    合包分包

    1,为什么需要合包、分包?

    这得从套接字协议说起

    socket_create ( int $domain , int $type , int $protocol ) : resource
    
    • domain 协议族
    • type 数据传输类型
    • protocol 协议

    详细请看php手册

    创建一个TCP套接字

    $socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
    

    传输类型SOCK_STREAM代表面向连接的套接字(stream流)。它被形象的比喻为“传送带”。TCP 协议即基于这种流式套接字。

    传送带特征:

    • 可靠
    • 顺序传输
    • 没有数据边界

    没有数据边界,即基于字节的传输方式。粘包处理正是体现“没有数据边界”这个特征。client、server端都需要处理粘包的问题。
    在这里插入图片描述
    上图来自《tcp/ip网络编程》

    图中一人为发送方,一人为接收方(并非发送方一定是客户端)。接收方为了提高效率,并非一有数据马上read,而是存在一个缓冲区(buffer),可能在缓冲区满后一次性读取,也可能未满时多次读取。

    这么说来,发送方发送多条数据,接收方可能一次性读取;或者发送方发送一条大量数据,接收方分多次读取。在面向连接的套接字中,read函数和write函数调用次数并无太大意义。

    通过实例来演示下:
    情况一:发送方发送多条数据,接收方一次性读取

    <?php //客户端
    $client = new swoole_client(SWOOLE_SOCK_TCP);
    $client->connect('127.0.0.1', 6001, -1);
    /**
     * 10条数据分十次发送
     */
    for ($i=0; $i < 11; $i++) {
    	$client->send("hello!");
    }
    $client->close();
    
    <?php //服务端
    $serv = new swoole_server("127.0.0.1", 6001);
    $serv->on('receive', function ($serv, $fd, $from_id, $data) {
        var_dump($data);
    });
    $serv->start();
    

    server端是一次性读取的:
    在这里插入图片描述

    情况二:发送方发送一条大量数据,接收方分多次读取

    <?php //客户端
    $client = new swoole_client(SWOOLE_SOCK_TCP);
    $client->connect('127.0.0.1', 6001, -1);
    /**
     * 发送一条较大的数据
     */
    $client->send(str_repeat('a',32*1024));
    $client->close();
    
    <?php //服务端
    $serv = new swoole_server("127.0.0.1", 6001);
    $serv->on('receive', function ($serv, $fd, $from_id, $data) {
        var_dump(strlen($data));
    });
    $serv->start();
    

    server端是多次读取的:
    在这里插入图片描述
    以上总结合包分包处理的原因是 tcp缓冲区 和 SOCK_STREAM协议无边界的特性,除了这两个原因还有TCP拥有拥塞控制,数据包可能会延后发送。这些在实际开发中需特别注意。

    2,如何解决?

    swoole文档在 入门指导>快速起步>网络通讯协议 中给了两种解决方案。

    第一种:EOF (end of file)
    通过特定的分隔符来确认完整的数据。

    <?php //服务端
    $serv = new swoole_server("127.0.0.1", 6001);
    //在接收方 设置两个选项
    $serv->set([
    	'open_eof_split'=>true,
    	'package_eof'=>"\r\n\r\n"
    	]);
    
    $serv->on('receive', function ($serv, $fd, $from_id, $data) {
        var_dump(strlen($data));
    });
    
    $serv->start();
    

    自动分包:

    <?php
    $client = new swoole_client(SWOOLE_SOCK_TCP);
    $client->connect('127.0.0.1', 6001, -1);
    
    /**
     * 10条数据分十次发送
     * 开启eof后数据结尾需加上自定义结束符,否则接收方无法接收到数据
     */
    for ($i=0; $i < 5; $i++) {
    	$client->send("hello!"."\r\n\r\n"); 
    }
    
    $client->close();
    

    在这里插入图片描述
    自动合包

    <?php
    $client = new swoole_client(SWOOLE_SOCK_TCP);
    $client->connect('127.0.0.1', 6001, -1);
    /**
     * 发送一条较大的数据
     */
    $client->send(str_repeat('a',32*1024)."\r\n\r\n");
    
    $client->close();
    

    在这里插入图片描述

    EOF方法,需保证数据中不能包含eof字符,否则会发生截取的数据不正确,但实际并不能保证数据中不包含eof字符。并且在截取数据时采用遍历数据进行eof字符匹配,有一定的性能消耗,因此通常使用第二种方法。
    swoole也推荐包头+包体的方法
    在这里插入图片描述

    第二种:固定包头+包体

    原理:
    在这里插入图片描述
    在数据data前,用几个字节保存data的长度,接收方根据长度来截取数据data。
    如包体data=‘aaaaa’,包头用2个字节保存data长度5。
    在这里插入图片描述
    接收方收到包后,先解析二进制格式包头,解析出5代表包体的长度为5,再从包(包体+包头=7长度)的第2字节(因包头占用2个字节长度)开始截取5的长度的数据即aaaaa。类似data = substr(包,2)。

    那么接下来的重点是如何定义包头:

    1. 确保包头的长度固定(用多少个字节保存数据的长度),让接收方知道从包的哪个位置开始截取(偏移量),因为数据长度是不确定的。
    2. 其次包头的固定长度尽量的小,不占用过多资源,那么使用二进制来存贮是非常合适的。
    3. 不同的计算机保存和解析数据时顺序是不一致的(主机字节序),如整数值1在发送方的存贮方式是这样的:00000000 00000000 00000000 00000001,如果接收方和发送方的主机字节序相反,它保存的是:00000001 00000000 00000000 00000000。打个不恰当的例子,如发送方发送1234,先发送高位的1(千位),接收方接收到1,因它和发送方保存数据的顺序正好相反,它先保存低位的,1则被保存到最低位1(个位),接收完变成4321。因此出现个概念叫“网络字节序”,统一发送数据的顺序,接收方按照固定的函数将这种顺序的数据转成自己主机的主机字节序保存。例如统一发送顺序为4(个)-3(十)-2(百)-1(千) ----->接收方清楚1是高位的。(只是举例子,实际是二进制的)。

    如何定义包头:
    在swoole文档中Server>配置选项>package_length_type列举了包头的类型
    在这里插入图片描述
    明白上边提到的三点,那么选择无符号的、网络字节序。即NnN能表示更多的整数值。

    固定包头+包体的原理模型:

    注意:只是演示这种方式的原理,有合包和分包的问题!

    <?php //客户端
    $client = new swoole_client(SWOOLE_SOCK_TCP);
    $client->connect('127.0.0.1', 6001, -1);
    /**
     * 打包
     */
    $body = 'aaaaa'; 
    //包头:将data的长度打包成4字节的二进制字符串
    $head = pack('N',strlen($body)); 
    $pack = $head.$body; //包头+包体
    
    $client->send($pack);
    $client->close();
    
    <?php //服务端
    $serv = new swoole_server("127.0.0.1", 6001);
    $serv->on('receive', function ($serv, $fd, $from_id, $data) {
    
        var_dump(strlen($data)); //包头+包体长度=9
       	$len = unpack('N',$data); //unpack将$data中的二进制字符串解压缩到数组中
        var_dump($len); //array(1=>5)
        echo $body = substr($data,4,$len[1]); //substr($data,4,5)
        
    });
    $serv->start();
    

    在这里插入图片描述
    swoole中的处理:
    在swoole文档中Server>配置选项>package_length_check中给了示例
    在这里插入图片描述

    这个设置是为了解决分包合包的问题,并没有自动处理封包解包的过程,这个要特别注意。

    客户端保持不变,只是更改为循环发送多条数据:

    <?php //客户端
    $client = new swoole_client(SWOOLE_SOCK_TCP);
    $client->connect('127.0.0.1', 6001, -1);
    /**
     * 打包
     */
    $body = 'aaaaa';
    $head = pack('N',strlen($body));
    $pack = $head.$body; 
    
    for ($i=0; $i < 6 ; $i++) {
    	$client->send($pack);
    }
    $client->close();
    
    <?php //服务端
    $serv = new swoole_server("127.0.0.1", 6001);
    $serv->set([
    	'open_length_check' => true, //开启打开包长检测特性
        'package_max_length' => 32*1024, //包的最大长度 过大会占用较多的输入缓冲区 下面单独介绍
        'package_length_type' => 'N', //包头长度类型
        'package_length_offset' => 0,  //length长度值在包头的第几个字节
        'package_body_offset' => 4, //从第几个字节开始计算包体长度
    ]);
    
    $serv->on('receive', function ($serv, $fd, $from_id, $data) {
    
       $len = unpack('N',$data);
       $body = substr($data,4,$len[1]);
       var_dump($body);
    });
    
    $serv->start();
    

    在这里插入图片描述

    注意:当server启用了包头+包体方式,那么client端必须发送包头+包体格式的数据,否则会报错。

    ’package_max_length’:

    表示服务端最大接收单次包的最大长度。

    开启open_length_check/open_eof_check自动分包合包后,swoole底层会进行数据包拼接。这时在数据包未收取完整时,所有数据都是保存在内存中的。如果1w个tcp连接在发送数据,每个连接发送1M,那么接收方就会用10G的内存来存贮。

    这是指swoole为了分包合包功能分配的内存而带来的注意事项,和输入输出缓冲区无关。

    <?php //服务端
    $serv = new swoole_server("127.0.0.1", 6001);
    $serv->set([
    	'worker_num'=>1,
    	'open_length_check' => true,
        'package_max_length' => 20*1024,
        'package_length_type' => 'N',
        'package_length_offset' => 0,
        'package_body_offset' => 4,
    ]);
    $serv->on('receive', function ($serv, $fd, $from_id, $data) {
       $len = unpack('N',$data);
       $body = substr($data,4,$len[1]);
       var_dump(strlen($body));
    });
    
    $serv->start();
    
    <?php //客户端
    $client = new swoole_client(SWOOLE_SOCK_TCP);
    $client->connect('127.0.0.1', 6001, -1);
    /**
     * 发送80*1024长度数据 大于了接收方设置的 'package_max_length'=20*1024
     */
    $body = str_repeat('a',80*1024);
    $head = pack('N',strlen($body));
    $pack = $head.$body;
    $client->send($pack);
    
    $client->close();
    

    报错信息:
    在这里插入图片描述
    为了说明分包合包不仅仅用于客户端向服务端发送,下面例子服务端向客户端发送,其实大部分是一样的,采用同步客户端,有个小细节需要注意,即配置选项要在connect之前,否则不会生效,所以特别贴出来。

    <?php
    $serv = new swoole_server("127.0.0.1", 6001);
    $serv->on('connect', function (swoole_server $serv, int $fd) {
       	$body = str_repeat('a',1000*1024);
    	$head = pack('N',strlen($body));
    	$pack = $head.$body;
    
    	$serv->send($fd,$pack);
    });
    $serv->on('receive',function($serv, $fd, $reactor_id, $data){
    	echo 'received';
    });
    
    $serv->start();
    
    <?php //客户端
    $client = new swoole_client(SWOOLE_SOCK_TCP);
    
    //注意同步客户端 设置选项在connect之前!
    $client->set(array(
        'open_length_check'     => 1,
        'package_length_type'   => 'N',
        'package_length_offset' => 0,  
        'package_body_offset'   => 4,   
        'package_max_length'    => 100*1024, 
    ));
    
    $client->connect('127.0.0.1', 6001, -1);
    
    $data = $client->recv();
    if($data){
    	$len = unpack('N',$data);
    	$body = substr($data,4,$len[1]);
    	var_dump(strlen($body));
    }
    
    $client->close();
    

    在这里插入图片描述

    展开全文
  • 依据属性 的语义关系, 将区间集信息系统分为两类: 析取( I 型) 和合取( II 型) 系统, 并对其分别提出了基于优势关系的粗 糙集模型, 讨论了相关性质. 最后用实例分析验证了所提出系统的有效性.</body&...
  • 显然,一个命题的析取范式和合取范式一定存在,但不一定是唯一的。为了将任意命题公式唯一地标准化,需要引入主范式。我们也会证明,为什么一个命题公式的主析取范式和主合取范式是唯一的。 6.2 主析取范式 6.2.1 极...
  • 使场景或精灵以灰度的形式显示,这是一般游戏制作中常常用到的效果,如:战棋游戏中当一个角色被使用过后,通常就会变成灰色...其实这是非常简单的,基本原理就是将一个点的RGB分开来求和,然后除以3,把得到的
  • c++真表实验报告

    2014-06-05 10:36:30
    本资源是关于c++真表课程实验的实验报告
  • 这个建筑风水布局一亿

    千次阅读 2016-10-14 12:32:17
    4.迎送和合局 在天环广场的北门位置环顾周围,地面上只能看到两个商家,一个是苹果一个是特斯拉。 这是为什么呢? 又是一个心机风水局: 特斯拉在西北方的一个转角处外侧,而苹果则在东南方的内凹处,...
  • } //主析取范式中的一个 void xiqu(Val* val,int num) { int j = 0; printf("("); for (int i = 0; i ; i++) { if (val->vaule[i]== 1+'0') { //e[j++] = val->ch[i]; if(i!=num-1) printf("%c&", val->ch[i]); ...
  • #include<stdio.h> #include<string> #include<iostream> #define num 3 #define Fvalue A[0]*!A[1]+A[2]*!A[0]+!A[2]*A[0]+!A[1]*A[0] using namespace std;...string a...
  • } 定义后缀表达式求函数 bool value()//后缀表达式求 { ch['T']=true;//定义map中T为true,F为false ch['F']=false; stack <char> c,s; s=s3;//复制后缀表达式 while(!s.empty())//计算后缀表达式 { char p=s....
  • 代码链接:pan.baidu.com/s/15inIth8Vl89R1CgQ_wYc2g 提取码:gf13 算法分析与设计第 1 次实验 ... 用分治法查找数组元素的最大和最小值 实验目的 ...
  • 对比比特币的 “UTXO” 余额模型,以太坊使用“账户”余额模型。 以太坊丰富了账户内容,除... ... 再配合以太坊虚拟机,让智能合约沙盒运行。 ...以太坊作为智能合约操作平台,将账户划分为两类:外部账户(EOAs)和合...
  • 命题逻辑等值演算

    千次阅读 2015-04-15 23:48:41
    逻辑公式在等值演算下也有标准形--范式,范式有两种:析取范式和合取范式。简单合取式和简单析取式定义2.2 命题变项及其否定统称作文字。仅有有限个文字构成的析取式称作简单析取式。仅有有限个文字构成的合取式称作...
  • HTTP协议之分段传输与分块编码

    千次阅读 2019-03-23 13:09:11
    目录 数据的分段传输 数据的分块编码(transfer-encoding) ... 数据的分段传输 ...那么,服务器端怎么判断客户端传来的数据已经发送完了,然后...我们客户端在发送给服务器端报文中有一个Connection 字段,一般这个...
  • 首先,谓词逻辑中的基本元素,常项、变项、谓词、量词等,不像句子,它们没有真值,因此无法用赋值函数赋予它们特定的。因此,在赋值函数之外,我们会引进【解释函数】的概念。它的任务就是将语言中的这些非句子...
  • 〉 因为C和D(在任何赋值下)等值,所以用 D替换C不会改变A的真值 〉 注意:不要求全部出现都替换 四、证明逻辑等价式和逻辑蕴涵式 常用来证明逻辑等价式的方法有如下几种方法: 〉 真表法:要证明 A╞╡B,A╞B...
  • 在这方面,Schönfinkel的前辈,包括弗雷格、罗素、怀特海已经做了大量工作,在《Principia Mathematica》(数学原理)中,已经将定义前的逻辑运算符从五个减少到两个:否定和析取,或者否定和合取、析取、蕴含中的...
  • 智能商业20讲--曾明.听后感悟

    万次阅读 2018-11-29 10:35:14
    内容属性: 生产时间2017年7月29日,内容保鲜期18个月,内容省略度5%, 内容类型:干货型。内容制作视角:全开放。文案状态:持续迭代,不断更新。 1月11日更新。 我发现最近自从跨年演讲...我觉的...
  • 基于JAVA的模块化开发框架JarsLink

    万次阅读 2018-03-26 08:47:30
    全称是Simple Object-oriented and Flexible Architecture,是一个轻量级的面向对象的,可扩展的应用架构,可以帮助降低复杂应用场景的系统熵,提升系统开发和运维效率 ) , 模块的父加载器是...
  • Lucene Search流程之二

    2019-02-28 20:28:06
    是SkipList主要应用场景,它除了应用于TOP_SCORE,还能用在多个结果集间做析取和合取运算上。 2.2. BooleanQuery 在真实的运用情景下,并非全是单个查询条件的,它更多的往往是多个条件的复合查询。布尔查询...
  • Linux内核调试的方式以及工具集锦

    万次阅读 多人点赞 2017-04-01 21:31:55
    CSDN GitHub Linux内核调试的方式以及工具集锦 LDD-LinuxDeviceDrivers/study/debug 本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可, 转载请注明出处, 谢谢合作 ...
  • Anis教授是多本书籍的编辑,也是160多种出版物的作者和合着者。 他是“国际高级机器人技术系统杂志”(IJARS)机器人软件工程专题的主编。 教授  Anis参与设计和开发了第一个用于控制和监测互联网无人机的基于云的...
  • 不投产坚果,锤子尚有品牌逼格,一旦投产坚果,则锤子就直接成为红米的同档次产品,品牌就分文不,在低价领域与强大的红米竞争更是败得一塌涂地。 也就是说,罗永浩的手机,应该主要专注于做UI系统,只做公版...
  • 如何实现iOS图书动画-第2部分(下)

    千次阅读 2015-10-16 09:57:28
    这个方法在Pop动画完成时执行清理动作:将BooksViewController的Collection View的背景色设回它开始的并显示封面。 在animateTransition(_:)方法里面,找到注释有“//POP”的else语句块,添加如下代码: /...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 699
精华内容 279
关键字:

和合值