GVKun编程网logo

累积布局偏移 (CLS) 问题在 wordpress 主题中

9

对于想了解累积布局偏移(CLS)问题在wordpress主题中的读者,本文将是一篇不可错过的文章,并且为您提供关于C#好代码学习笔记(1):文件操作、读取文件、Debug/Trace类、Conditi

对于想了解累积布局偏移 (CLS) 问题在 wordpress 主题中的读者,本文将是一篇不可错过的文章,并且为您提供关于C# 好代码学习笔记(1):文件操作、读取文件、Debug/Trace 类、Conditional条件编译、CLS、cls 挂钩或错误使用中的内存泄漏? CLS 挂钩异步钩子、java#Class cls && T t、Manager isn''t accessible via %s instances" % cls.__name_ 报错信息的有价值信息。

本文目录一览:

累积布局偏移 (CLS) 问题在 wordpress 主题中

累积布局偏移 (CLS) 问题在 wordpress 主题中

如何解决累积布局偏移 (CLS) 问题在 wordpress 主题中

我的 wordpress/woocommerce 商店中有付费主题,而在 pagespeed 洞察中,我遇到了无法解决的 CLS 问题。我尝试询问主题的支持团队,但他们没有帮助我。 pagespeed 告诉我问题出在这个元素上:

  1. <div class="large-6 small-12 columns product-info summary entry-summary rtl-left">

示例页面为: page link

我不想直接编辑主题。是否可以添加adicional css或片段? 谢谢你的帮助。

C# 好代码学习笔记(1):文件操作、读取文件、Debug/Trace 类、Conditional条件编译、CLS

C# 好代码学习笔记(1):文件操作、读取文件、Debug/Trace 类、Conditional条件编译、CLS

目录
  • 1,文件操作
  • 2,读取文件
  • 3,Debug 、Trace类
  • 4,条件编译
  • 5,MethodImpl 特性
  • 5,CLSCompliantAttribute
  • 6,必要时自定义类型别名

目录:

1,文件操作

2,Debug、Trace类

3,条件编译

4,MethodImpl 特性

5,CLSComplianAttribute

6,必要时自定义类型别名

最近在阅读 .NET Core Runtime 的源码,参考大佬的代码,学习编写技巧和提高代码水平。学习过程中将学习心得和值得应用到项目中的代码片段记录下来,供日后查阅。

1,文件操作

这段代码在 System.Private.CoreLib 下,对 System.IO.File 中的代码进行精简,供 CLR 使用。

当使用文件时,要提前判断文件路径是否存在,日常项目中要使用到文件的地方应该不少,可以统一一个判断文件是否存在的方法:

  public static bool Exists(string? path)  {   try   {    // 可以将 string? 改成 string    if (path == null)     return false;    if (path.Length == 0)     return false;    path = Path.GetFullPath(path);    // After normalizing, check whether path ends in directory separator.    // Otherwise, FillAttributeInfo removes it and we may return a false positive.    // GetFullPath should never return null    Debug.Assert(path != null, "File.Exists: GetFullPath returned null");    if (path.Length > 0 && PathInternal.IsDirectorySeparator(path[^1]))    {     return false;    }    return InternalExists(path);   }   catch (ArgumentException) { }   catch (NotSupportedException) { } // Security can throw this on ":"   catch (SecurityException) { }   catch (IOException) { }   catch (UnauthorizedAccessException) { }   return false;  }

建议项目中对路径进行最终处理的时候,都转换为绝对路径:

Path.GetFullPath(path)

当然,相对路径会被 .NET 正确识别,但是对于运维排查问题和各方面考虑,绝对路径容易定位具体位置和排错。

在编写代码时,使用相对路径,不要写死,提高灵活性;在运行阶段将其转为绝对路径;

上面的 NotSupportedException 等异常是操作文件中可能出现的各种异常情况,对于跨平台应用来说,这些异常可能都是很常见的,提前将其异常类型识别处理,可以优化文件处理逻辑以及便于筛查处理错误。

2,读取文件

这段代码在 System.Private.CoreLib 中。

有个读取文件转换为 byte[] 的方法如下:

  public static byte[] ReadAllBytes(string path)  {   // bufferSize == 1 used to avoid unnecessary buffer in FileStream   using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 1))   {    long fileLength = fs.Length;    if (fileLength > int.MaxValue)     throw new IOException(SR.IO_FileTooLong2GB);    int index = 0;    int count = (int)fileLength;    byte[] bytes = new byte[count];    while (count > 0)    {     int n = fs.Read(bytes, index, count);     if (n == 0)      throw Error.GetEndOfFile();     index += n;     count -= n;    }    return bytes;   }  }

可以看到 FileStream 的使用,如果单纯是读取文件内容,可以参考里面的代码:

  FileStream fs = new FileStream(path,          FileMode.Open,          FileAccess.Read,          FileShare.Read,          bufferSize: 1)

上面的代码同样也存在 File.ReadAllBytes 与之对应, File.ReadAllBytes 内部是使用 InternalReadAllBytes 来处理文档读取:

  private static byte[] InternalReadAllBytes(String path, bool checkHost)  {   byte[] bytes;   // 此 FileStream 的构造函数不是 public ,开发者不能使用   using(FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read,     FileStream.DefaultBufferSize, FileOptions.None, Path.GetFileName(path), false, false, checkHost)) {    // Do a blocking read    int index = 0;    long fileLength = fs.Length;    if (fileLength > Int32.MaxValue)     throw new IOException(Environment.GetResourceString("IO.IO_FileTooLong2GB"));    int count = (int) fileLength;    bytes = new byte[count];    while(count > 0) {     int n = fs.Read(bytes, index, count);     if (n == 0)      __Error.EndOfFile();     index += n;     count -= n;    }   }   return bytes;  }

这段说明我们可以放心使用 File 静态类中的函数,因为里面已经处理好一些逻辑了,并且自动释放文件。

如果我们手动 new FileStream ,则要判断一些情况,以免使用时报错,最好参考一下上面的代码。

.NET 文件流缓存大小默认是 4096 字节:

internal const int DefaultBufferSize = 4096;

这段代码在 File 类中定义,开发者不能设置缓存块的大小,大多数情况下,4k 是最优的块大小。

ReadAllBytes 的文件大小上限是 2 GB。

3,Debug 、Trace类

这两个类的命名空间为 System.Diagnostics,Debug 、Trace 提供一组有助于调试代码的方法和属性。

Debug 中的所有函数都不会在 Release 中有效,并且所有输出流不会在控制台显示,必须注册侦听器才能读取这些流

Debug 可以打印调试信息并使用断言检查逻辑,使代码更可靠,而不会影响发运产品的性能和代码大小

这类输出方法有 Write 、WriteLine 、 WriteIf 和 WriteLineIf 等,这里输出不会直接打印到控制台

如需将调试信息打印到控制台,可以注册侦听器:

ConsoleTraceListener console = new ConsoleTraceListener();Trace.Listeners.Add(console);

注意, .NET Core 2.x 以上 Debug 没有 Listeners ,因为 Debug 使用的是 Trace 的侦听器。

我们可以给 Trace.Listeners 注册侦听器,这样相对于 Debug 等效设置侦听器。

  Trace.Listeners.Add(new TextWriterTraceListener(Console.Out));  Debug.WriteLine("aa");

.NET Core 中的监听器都继承了 TraceListener,如 TextWriterTraceListener、ConsoleTraceListener、DefaultTraceListener。

如果需要输出到文件中,可以自行继承 TextWriterTraceListener ,编写文件流输出,也可以使用 DelimitedListTraceListener。

示例:

TraceListener listener = new DelimitedListTraceListener(@"C:\debugfile.txt");  // Add listener.  Debug.Listeners.Add(listener);  // Write and flush.  Debug.WriteLine("Welcome");

处理上述方法输出控制台,也可以使用

ConsoleTraceListener console=......Listeners.Add(console);// 等效于var console = new TextWriterTraceListener(Console.Out)

为了格式化输出流,可以使用 一下属性控制排版:

属性 说明
AutoFlush 获取或设置一个值,通过该值指示每次写入后是否应在 Flush() 上调用 Listeners。
IndentLevel 获取或设置缩进级别。
IndentSize 获取或设置缩进的空格数。
  // 1.  Debug.WriteLine("One");  // Indent and then unindent after writing.  Debug.Indent();  Debug.WriteLine("Two");  Debug.WriteLine("Three");  Debug.Unindent();  // End.  Debug.WriteLine("Four");  // Sleep.  System.Threading.Thread.Sleep(10000);
One Two ThreeFour

.Assert() 方法对我们调试程序很有帮助,Assert 向开发人员发送一个强消息。在 IDE 中,断言会中断程序的正常操作,但不会终止应用程序。

.Assert() 的最直观效果是输出程序的断言位置。

  Trace.Listeners.Add(new TextWriterTraceListener(Console.Out));  int value = -1;  // A.  // If va.........

cls 挂钩或错误使用中的内存泄漏? CLS 挂钩异步钩子

cls 挂钩或错误使用中的内存泄漏? CLS 挂钩异步钩子

正如向 OP 指出的那样,用法肯定是不正确的。

OP 应该只执行一次 ns.run(),并且 run 中的所有内容都将具有相同的上下文。

看看这个正确用法的例子:

var createNamespace = require('cls-hooked').createNamespace;
 
var writer = createNamespace('writer');
writer.run(function () {
  writer.set('value',0);
 
  requestHandler();
});
 
function requestHandler() {
  writer.run(function(outer) {
    // writer.get('value') returns 0
    // outer.value is 0
    writer.set('value',1);
    // writer.get('value') returns 1
    // outer.value is 1
    process.nextTick(function() {
      // writer.get('value') returns 1
      // outer.value is 1
      writer.run(function(inner) {
        // writer.get('value') returns 1
        // outer.value is 1
        // inner.value is 1
        writer.set('value',2);
        // writer.get('value') returns 2
        // outer.value is 1
        // inner.value is 2
      });
    });
  });
 
  setTimeout(function() {
    // runs with the default context,because nested contexts have ended
    console.log(writer.get('value')); // prints 0
  },1000);
}

此外,cls-hooked 中的实现确实表明上下文是通过异步钩子回调 destroy(asyncId)

destroy(asyncID)asyncId 对应的资源销毁后调用。它也被嵌入器 API 异步调用。某些 resources 依赖垃圾收集进行清理,因此如果对传递给 init 的资源对象进行了引用,则可能永远不会调用 destroy,从而导致内存泄漏应用。如果资源不依赖于垃圾收集,那么这将不是问题。 https://github.com/Jeff-Lewis/cls-hooked/blob/0ff594bf6b2edd6fb046b10b67363c3213e4726c/context.js#L416-L425

这是我的存储库,通过使用 autocannon 用大量请求轰炸服务器来比较和测试内存使用情况 https://github.com/Darkripper214/AsyncMemoryTest

根据测试,heap 的利用率几乎没有增加(正如预期的那样,因为我们正在处理 HTTP 请求)。

CLS-Hooked 和 Async-Hook 的内存使用

目的

存储库是一个微型测试,用于查看使用 cls-hookedasync-hookNode.js 内传递上下文时如何利用内存。

用法

  1. npm run start 用于 CLS 挂钩服务器 npm run async 用于异步挂钩服务器

  2. 转到 Chrome 并粘贴 chrome://inspect

  3. 点击inspect访问服务器的开发工具

devtools

  1. 转到memory选项卡,您可以在用请求轰炸服务器之前、之中和之后拍摄快照并检查heap

  2. node benchmark.js 开始用请求轰炸服务器。这是由 autocannon 提供支持,您可能需要增加 connectionsduration 以查看差异。

结果

CLS 挂钩

统计 1% 2.5% 50% 97.5% 平均 标准 最大
请求/秒 839 839 871 897 870.74 14.23 839
字节/秒 237kB 237kB 246kB 253kB 246kB 4.01kB 237kB

每秒采样一次的请求/字节计数(请注意,这是在附加调试器的情况下运行的,每秒性能会受到影响)

15.05 秒内 13k 个请求,3.68 MB 读取

cls-hook

cls-hooked graph

异步钩子

统计 1% 2.5% 50% 97.5% 平均 标准 最大
请求/秒 300 300 347 400 346.4 31.35 300
字节/秒 84.6kB 84.6kB 97.9kB 113kB 97.7kB 8.84kB 84.6kB

每秒采样一次的请求/字节计数(请注意,这是在附加调试器的情况下运行的,并且有大量 debug() 消息显示它是如何被破坏的,每秒性能会受到影响)

>

15.15 秒内 5k 个请求,读取 1.47 MB​​

async

async-graph

编辑 1

OP 抱怨每次执行 store 时设置的 _context 的长度。如前所述,OP 的测试方式不正确,因为它在循环中运行。

OP 所抱怨的场景只会在 namespace.run() 执行一些包含或包含 namespace.run() 的回调时发生。

async function

那么为什么_context 没有被清除?这是因为 async function t3() {} // This async function will cause _context length to not be cleared function t2() { t3(); } function t1() { for (let i = 0; i < 500; i++) { session.run(t2); } } t1(); 将无法在 node.js async function t3 中运行,因为 event loop 持续运行,因此项目几乎无限附加到 {{1} }.

为了证明这是由于这种行为,我更新了 repo 以包含一个文件 synchronous for loop,该文件可以使用 _context 运行,该文件在两者之间显式运行垃圾收集,以及垃圾集合不会影响 cls-gc.js 的长度。

npm run gc_context 的执行过程中 _context 的长度会很长,因为两者都是同步的。但是,在调用 t1() 回调之后,t2() 的长度大约是正确的。请使用调试器进行检查。

_context 的长度将在 setTimeout

_context

java#Class<T> cls && T t

java#Class cls && T t

/**
     * 在阅读别人写的源代码中,有时候可以看到同样功能的泛型方法中的参数可以写成 T t 或者 Class<T> cls
     * 那么,两者有什么区别呢?
     * 
     * Class类,是代表加载到jvm中的类的字节码,这个类本身是泛型类,其后可以加<具体类>从而表示具体类的字节码类型,
     * 于是Class<T>,就代表了类T的字节码类型。于是Class<T> cls中的cls就是类型T的字节码对象实例。
     * 
     * 另一方面:
     * T t 就很好理解了,T是方法返回值前面的泛型列表中指定的泛型类型,小t表示这个类型的对象。
     *
     * 请参考如下的三个方法仔细体会。
     *
     */


    /**
     * 接受任意类型的对象,并返回该对象。
     * @param t
     * @param <T>
     * @return
     */
    public <T> T doSomething0(T t) {
        return t;
    }

    /**
     * 接受任意字节码实例,并通过该字节码创建实例并返回。
     * 但是由于方法指定返回类型是T,所以返回时候要做强制类型转换,
     * 因此传入的cls应该是返回值t对应类的字节码对象。
     * 由于是强转没有做类型检查,所有使用了@SupperessWarning("unchecked")压制编译器产生的警告。
     * @param cls
     * @param <T>
     * @return
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    public <T> T doSomething1(Class cls) throws Exception {
        return (T) cls.newInstance();
    }

    /**
     * 接受T类型的字节码对象,并根据此字节码对象创建对应类的实例并返回
     * @param cls
     * @param <T>
     * @return
     * @throws Exception
     */
    public <T> T doSomething2(Class<T> cls) throws Exception {
        return cls.newInstance();
    }


    /**
     * 最后,
     * Class对象实例可以用任意类型对象的.getClass()方法取得,
     * Class对象的实例也可用任意类型.class 直接表示。
     * 
     * Class<String> stringClass = String.class;
     * Class<? extends String> a.getClass();
     */

 

Manager isn''t accessible via %s instances

Manager isn''t accessible via %s instances" % cls.__name_ 报错信息

Django 的 orm 中使用到了元类和描述符这些高级知识,了解一下的可以看看这篇文章。

元类其实就是用来定义类的,我的理解是这样的:当很多类有相同的属性,那么就可以提取这些相同的属性到一个类中,元类就是用来封装那些的,或者给某些类添加一些属性,定制类。你看看 Django model 写的代码有多少,而背后元类默默做了很多东西。

Django model 需要继承自 models.Model,跟踪进去发现 class Model(metaclass=ModelBase):Model 其实是根据 ModelBase 构建的,在实例化的时候,会首先执行 ModelBase__new__ 方法。里面为我们封装了 _meta 这么一个属性,具体的可以看看源码。

我们查询数据的时候一直用到 obejcts 方法,那么它是哪来的呢?在封装self._meta 后调用了 _prepare,在它里面发现了一个管理器 manager

 

if not opts.managers:
    if any(f.name == ''objects'' for f in opts.fields):
        raise ValueError(
            "Model %s must specify a custom Manager, because it has a "
            "field named ''objects''." % cls.__name__
        )
    manager = Manager()
    manager.auto_created = True
    cls.add_to_class(''objects'', manager)

这里使用了 manager ,然后注册了 objects。那么来看看 Manager:

class Manager(BaseManager.from_queryset(QuerySet)):
    pass

什么也没做,只是根据 BaseManager 的类方法构造了一个类,然后继承了它,就是 QuerySet,到这里,你就大体明白了吧,我们一般查询出来的都是一个 QuerySet 对象。

@classmethod
def from_queryset(cls, queryset_class, class_name=None):
    if class_name is None:
        class_name = ''%sFrom%s'' % (cls.__name__, queryset_class.__name__)
    class_dict = {
        ''_queryset_class'': queryset_class,
    }
    class_dict.update(cls._get_queryset_methods(queryset_class))
    return type(class_name, (cls,), class_dict)

这里使用了 type 来创造一个类。
其实准确来说,Manager 应该是继承了两个类 BaseManager 和 QuertSet

再来看看 add_to_class:

def add_to_class(cls, name, value):
    # We should call the contribute_to_class method only if it''s bound
    if not inspect.isclass(value) and hasattr(value, ''contribute_to_class''):
        value.contribute_to_class(cls, name)
    else:
        setattr(cls, name, value)

这里又调用了 manager 的 contribute_to_class 方法:

def contribute_to_class(self, model, name):
    if not self.name:
        self.name = name
    self.model = model

    setattr(model, name, ManagerDescriptor(self))

    model._meta.add_manager(self)

又给 objects 赋值了一个 ManagerDescriptor 实例,这个是干嘛的呢?属性描述符:

class ManagerDescriptor:

    def __init__(self, manager):
        self.manager = manager

    def __get__(self, instance, cls=None):
        if instance is not None:
            raise AttributeError("Manager isn''t accessible via %s instances" % cls.__name__)

        if cls._meta.abstract:
            raise AttributeError("Manager isn''t available; %s is abstract" % (
                cls._meta.object_name,
            ))

        if cls._meta.swapped:
            raise AttributeError(
                "Manager isn''t available; ''%s.%s'' has been swapped for ''%s''" % (
                    cls._meta.app_label,
                    cls._meta.object_name,
                    cls._meta.swapped,
                )
            )

        return cls._meta.managers_map[self.manager.name]

这里做了一些限制。
Django orm 四个重要类:
ModelQuerySetQueryObjects
QuerySet 主要是定义了一些接口,如 filter, count 等。它是惰性求值的,它并不直接求出值,只是在需要的时候查询。
Query 实现 sql 的拼接,它将语句交给 sql 编译对象。

一次查询过程:


Django 模型查询过程

如果还想深入,可以看看  QuerySet 的源码。
ps: objects 是一个  Manager 实例,而
Manager 是一个空壳,它继承自  QuerySet

关于累积布局偏移 (CLS) 问题在 wordpress 主题中的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于C# 好代码学习笔记(1):文件操作、读取文件、Debug/Trace 类、Conditional条件编译、CLS、cls 挂钩或错误使用中的内存泄漏? CLS 挂钩异步钩子、java#Class cls && T t、Manager isn''t accessible via %s instances" % cls.__name_ 报错信息的相关信息,请在本站寻找。

本文标签: