首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >[源码解析] 并行分布式框架 Celery 之 worker 启动 (1)

[源码解析] 并行分布式框架 Celery 之 worker 启动 (1)

作者头像
罗西的思考
发布于 2021-04-01 02:39:19
发布于 2021-04-01 02:39:19
1.1K00
代码可运行
举报
文章被收录于专栏:罗西的思考罗西的思考
运行总次数:0
代码可运行

0x00 摘要

Celery是一个简单、灵活且可靠的,处理大量消息的分布式系统,专注于实时处理的异步任务队列,同时也支持任务调度。Celery 是调用其Worker 组件来完成具体任务处理。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ celery --app=proj worker -l INFO
$ celery -A proj worker -l INFO -Q hipri,lopri
$ celery -A proj worker --concurrency=4
$ celery -A proj worker --concurrency=1000 -P eventlet
$ celery worker --autoscale=10,0

所以我们本文就来讲解 worker 的启动过程。

0x01 Celery的架构

前面我们用几篇文章分析了 Kombu,为 Celery 的分析打下了基础。

下面我们再回顾下 Celery 的结构。Celery的架构图如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 +-----------+            +--------------+
 | Producer  |            |  Celery Beat |
 +-------+---+            +----+---------+
         |                     |
         |                     |
         v                     v

       +-------------------------+
       |          Broker         |
       +------------+------------+
                    |
                    |
                    |
     +-------------------------------+
     |              |                |
     v              v                v
+----+-----+   +----+------+   +-----+----+
| Exchange |   |  Exchange |   | Exchange |
+----+-----+   +----+------+   +----+-----+
     |              |               |
     v              v               v

  +-----+       +-------+       +-------+
  |queue|       | queue |       | queue |
  +--+--+       +---+---+       +---+---+
     |              |               |
     |              |               |
     v              v               v

+---------+     +--------+     +----------+
| worker  |     | Worker |     |  Worker  |
+-----+---+     +---+----+     +----+-----+
      |             |               |
      |             |               |
      +-----------------------------+
                    |
                    |
                    v
                +---+-----+
                | backend |
                +---------+

0x02 示例代码

其实网上难以找到调试Celery worker的办法。我们可以去其源码看看,发现如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# def test_worker_main(self):
#     from celery.bin import worker as worker_bin
#
#     class worker(worker_bin.worker):
#
#         def execute_from_commandline(self, argv):
#             return argv
#
#     prev, worker_bin.worker = worker_bin.worker, worker
#     try:
#         ret = self.app.worker_main(argv=['--version'])
#         assert ret == ['--version']
#     finally:
#         worker_bin.worker = prev

所以我们可以模仿来进行,使用如下启动worker,进行调试。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
from celery import Celery

app = Celery('tasks', broker='redis://localhost:6379')

@app.task()
def add(x, y):
    return x + y

if __name__ == '__main__':
    app.worker_main(argv=['worker'])

0x03 逻辑概述

当启动一个worker的时候,这个worker会与broker建立链接(tcp长链接),然后如果有数据传输,则会创建相应的channel, 这个连接可以有多个channel。然后,worker就会去borker的队列里面取相应的task来进行消费了,这也是典型的消费者生产者模式。

这个worker主要是有四部分组成的,task_pool, consumer, scheduler, mediator。其中,task_pool主要是用来存放的是一些worker,当启动了一个worker,并且提供并发参数的时候,会将一些worker放在这里面。

celery默认的并发方式是prefork,也就是多进程的方式,这里只是celery对multiprocessing pool进行了轻量的改造,然后给了一个新的名字叫做prefork,这个pool与多进程的进程池的区别就是这个task_pool只是存放一些运行的worker。

consumer也就是消费者,主要是从broker那里接受一些message,然后将message转化为celery.worker.request.Request 的一个实例。

Celery 在适当的时候,会把这个请求包装进Task中,Task就是用装饰器app_celery.task()装饰的函数所生成的类,所以可以在自定义的任务函数中使用这个请求参数,获取一些关键的信息。此时,已经了解了task_pool和consumer。

接下来,这个worker具有两套数据结构,这两套数据结构是并行运行的,他们分别是 'ET时刻表' 、就绪队列。

就绪队列:那些 立刻就需要运行的task, 这些task到达worker的时候会被放到这个就绪队列中等待consumer执行。

我们下面看看如何启动Celery

0x04 Celery应用

程序首先会来到Celery类,这是Celery的应用。

可以看到主要就是:各种类名称,TLS, 初始化之后的各种signal。

位置在:celery/app/base.py,其定义如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Celery:
    """Celery application."""

    amqp_cls = 'celery.app.amqp:AMQP'
    backend_cls = None
    events_cls = 'celery.app.events:Events'
    loader_cls = None
    log_cls = 'celery.app.log:Logging'
    control_cls = 'celery.app.control:Control'
    task_cls = 'celery.app.task:Task'
    registry_cls = 'celery.app.registry:TaskRegistry'

    #: Thread local storage.
    _local = None
    _fixups = None
    _pool = None
    _conf = None
    _after_fork_registered = False

    #: Signal sent when app is loading configuration.
    on_configure = None

    #: Signal sent after app has prepared the configuration.
    on_after_configure = None

    #: Signal sent after app has been finalized.
    on_after_finalize = None

    #: Signal sent by every new process after fork.
    on_after_fork = None

对于我们的示例代码,入口是:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def worker_main(self, argv=None):
    if argv is None:
        argv = sys.argv

    if 'worker' not in argv:
        raise ValueError(
            "The worker sub-command must be specified in argv.\n"
            "Use app.start() to programmatically start other commands."
        )

    self.start(argv=argv)

4.1 添加子command

celery/bin/celery.py 会进行添加 子command,我们可以看出来。

这些 Commnd 是可以在命令行作为子命令直接使用的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
celery.add_command(purge)
celery.add_command(call)
celery.add_command(beat)
celery.add_command(list_)
celery.add_command(result)
celery.add_command(migrate)
celery.add_command(status)
celery.add_command(worker)
celery.add_command(events)
celery.add_command(inspect)
celery.add_command(control)
celery.add_command(graph)
celery.add_command(upgrade)
celery.add_command(logtool)
celery.add_command(amqp)
celery.add_command(shell)
celery.add_command(multi)

每一个都是command。我们以worker为例,具体如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
worker = {CeleryDaemonCommand} <CeleryDaemonCommand worker>
 add_help_option = {bool} True
 allow_extra_args = {bool} False
 allow_interspersed_args = {bool} True
 context_settings = {dict: 1} {'allow_extra_args': True}
 epilog = {NoneType} None
 name = {str} 'worker'
 options_metavar = {str} '[OPTIONS]'
 params = {list: 32} [<CeleryOption hostname>, ...... , <CeleryOption executable>]

4.2 入口点

然后会引入Celery 命令入口点 Celery。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def start(self, argv=None):
    from celery.bin.celery import celery

    celery.params[0].default = self

    try:
        celery.main(args=argv, standalone_mode=False)
    except Exit as e:
        return e.exit_code
    finally:
        celery.params[0].default = None

4.3 缓存属性cached_property

Celery 中,大量的成员变量是被cached_property修饰的

使用 cached_property修饰过的函数,就变成是对象的属性,该对象第一次引用该属性时,会调用函数,对象第二次引用该属性时就直接从词典中取了,即 Caches the return value of the get method on first call。

很多知名Python项目都自己实现过 cached_property,比如Werkzeug,Django

因为太有用,所以 Python 3.8 给 functools 模块添加了 cached_property 类,这样就有了官方的实现。

Celery 的代码举例如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @cached_property
    def Worker(self):
        """Worker application.
        """
        return self.subclass_with_self('celery.apps.worker:Worker')

    @cached_property
    def Task(self):
        """Base task class for this app."""
        return self.create_task_cls()

    @property
    def pool(self):
        """Broker connection pool: :class:`~@pool`.
        """
        if self._pool is None:
            self._ensure_after_fork()
            limit = self.conf.broker_pool_limit
            pools.set_limit(limit)
            self._pool = pools.connections[self.connection_for_write()]
        return self._pool

所以,最终,Celery的内容应该是这样的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
app = {Celery} <Celery tasks at 0x7fb8e1538400>
 AsyncResult = {type} <class 'celery.result.AsyncResult'>
 Beat = {type} <class 'celery.apps.beat.Beat'>
 GroupResult = {type} <class 'celery.result.GroupResult'>
 Pickler = {type} <class 'celery.app.utils.AppPickler'>
 ResultSet = {type} <class 'celery.result.ResultSet'>
 Task = {type} <class 'celery.app.task.Task'>
 WorkController = {type} <class 'celery.worker.worker.WorkController'>
 Worker = {type} <class 'celery.apps.worker.Worker'>
 amqp = {AMQP} <celery.app.amqp.AMQP object at 0x7fb8e2444860>
 annotations = {tuple: 0} ()
 autofinalize = {bool} True
 backend = {DisabledBackend} <celery.backends.base.DisabledBackend object at 0x7fb8e25fd668>
 builtin_fixups = {set: 1} {'celery.fixups.django:fixup'}
 clock = {LamportClock} 1
 conf = {Settings: 163} Settings({'broker_url': 'redis://localhost:6379', 'deprecated_settings': set(), 'cache_...
 configured = {bool} True
 control = {Control} <celery.app.control.Control object at 0x7fb8e2585f98>
 current_task = {NoneType} None
 current_worker_task = {NoneType} None
 events = {Events} <celery.app.events.Events object at 0x7fb8e25ecb70>
 loader = {AppLoader} <celery.loaders.app.AppLoader object at 0x7fb8e237a4a8>
 main = {str} 'tasks'
 on_after_configure = {Signal} <Signal: app.on_after_configure providing_args={'source'}>
 on_after_finalize = {Signal} <Signal: app.on_after_finalize providing_args=set()>
 on_after_fork = {Signal} <Signal: app.on_after_fork providing_args=set()>
 on_configure = {Signal} <Signal: app.on_configure providing_args=set()>
 pool = {ConnectionPool} <kombu.connection.ConnectionPool object at 0x7fb8e26e9e80>
 producer_pool = {ProducerPool} <kombu.pools.ProducerPool object at 0x7fb8e26f02b0>
 registry_cls = {type} <class 'celery.app.registry.TaskRegistry'>
 set_as_current = {bool} True
 steps = {defaultdict: 2} defaultdict(<class 'set'>, {'worker': set(), 'consumer': set()})
 tasks = {TaskRegistry: 10} {'celery.chain': <@task: celery.chain of tasks at 0x7fb8e1538400>, 'celery.starmap': <@task: celery.starmap of tasks at 0x7fb8e1538400>, 'celery.chord': <@task: celery.chord of tasks at 0x7fb8e1538400>, 'celery.backend_cleanup': <@task: celery.backend_clea
 user_options = {defaultdict: 0} defaultdict(<class 'set'>, {})

具体部分成员变量举例如下图:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
+---------------------------------------+
|  Celery                               |
|                                       |
|                              Beat+-----------> celery.apps.beat.Beat
|                                       |
|                              Task+-----------> celery.app.task.Task
|                                       |
|                     WorkController+----------> celery.worker.worker.WorkController
|                                       |
|                            Worker+-----------> celery.apps.worker.Worker
|                                       |
|                              amqp +----------> celery.app.amqp.AMQP
|                                       |
|                           control +----------> celery.app.control.Control
|                                       |
|                            events  +---------> celery.app.events.Events
|                                       |
|                            loader +----------> celery.loaders.app.AppLoader
|                                       |
|                              pool +----------> kombu.connection.ConnectionPool
|                                       |
|                     producer_pool +----------> kombu.pools.ProducerPool
|                                       |
|                             tasks +----------> TaskRegistry
|                                       |
|                                       |
+---------------------------------------+

0x05 Celery 命令

Celery的命令总入口为celery方法,具体在:celery/bin/celery.py。

代码缩减版如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@click.pass_context
def celery(ctx, app, broker, result_backend, loader, config, workdir,
           no_color, quiet, version):
    """Celery command entrypoint."""

    if loader:
        # Default app takes loader from this env (Issue #1066).
        os.environ['CELERY_LOADER'] = loader
    if broker:
        os.environ['CELERY_BROKER_URL'] = broker
    if result_backend:
        os.environ['CELERY_RESULT_BACKEND'] = result_backend
    if config:
        os.environ['CELERY_CONFIG_MODULE'] = config
    ctx.obj = CLIContext(app=app, no_color=no_color, workdir=workdir,
                         quiet=quiet)

    # User options
    worker.params.extend(ctx.obj.app.user_options.get('worker', []))
    beat.params.extend(ctx.obj.app.user_options.get('beat', []))
    events.params.extend(ctx.obj.app.user_options.get('events', []))

    for command in celery.commands.values():
        command.params.extend(ctx.obj.app.user_options.get('preload', []))

在方法中,会遍历celery.commands,拓展param,具体如下。这些 commands 就是之前刚刚提到的子Command:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
celery.commands = 
 'report' = {CeleryCommand} <CeleryCommand report>
 'purge' = {CeleryCommand} <CeleryCommand purge>
 'call' = {CeleryCommand} <CeleryCommand call>
 'beat' = {CeleryDaemonCommand} <CeleryDaemonCommand beat>
 'list' = {Group} <Group list>
 'result' = {CeleryCommand} <CeleryCommand result>
 'migrate' = {CeleryCommand} <CeleryCommand migrate>
 'status' = {CeleryCommand} <CeleryCommand status>
 'worker' = {CeleryDaemonCommand} <CeleryDaemonCommand worker>
 'events' = {CeleryDaemonCommand} <CeleryDaemonCommand events>
 'inspect' = {CeleryCommand} <CeleryCommand inspect>
 'control' = {CeleryCommand} <CeleryCommand control>
 'graph' = {Group} <Group graph>
 'upgrade' = {Group} <Group upgrade>
 'logtool' = {Group} <Group logtool>
 'amqp' = {Group} <Group amqp>
 'shell' = {CeleryCommand} <CeleryCommand shell>
 'multi' = {CeleryCommand} <CeleryCommand multi>

0x06 worker 子命令

Work子命令是 Command 总命令的一员,也是我们直接在命令行加入 worker 参数时候,调用到的子命令。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ celery -A proj worker -l INFO -Q hipri,lopri

worker 子命令继承了click.BaseCommand,为。

定义在celery/bin/worker.py。

因此如下代码间接调用到 worker 命令:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
celery.main(args=argv, standalone_mode=False)

定义如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def worker(ctx, hostname=None, pool_cls=None, app=None, uid=None, gid=None,
           loglevel=None, logfile=None, pidfile=None, statedb=None,
           **kwargs):
    """Start worker instance.

    Examples
    --------
    $ celery --app=proj worker -l INFO
    $ celery -A proj worker -l INFO -Q hipri,lopri
    $ celery -A proj worker --concurrency=4
    $ celery -A proj worker --concurrency=1000 -P eventlet
    $ celery worker --autoscale=10,0

    """
    app = ctx.obj.app
    maybe_drop_privileges(uid=uid, gid=gid)
    worker = app.Worker(
        hostname=hostname, pool_cls=pool_cls, loglevel=loglevel,
        logfile=logfile,  # node format handled by celery.app.log.setup
        pidfile=node_format(pidfile, hostname),
        statedb=node_format(statedb, hostname),
        no_color=ctx.obj.no_color,
        **kwargs)
    worker.start()
    return worker.exitcode

此时流程如下图,可以看到,从 Celery 应用就进入到了具体的 worker 命令:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
      +----------+
      |   User   |
      +----+-----+
           |
           |  worker_main
           |
           v
 +---------+------------+
 |        Celery        |
 |                      |
 |  Celery application  |
 |  celery/app/base.py  |
 |                      |
 +---------+------------+
           |
           |  celery.main
           |
           v
 +---------+------------+
 |  @click.pass_context |
 |       celery         |
 |                      |
 |                      |
 |    CeleryCommand     |
 | celery/bin/celery.py |
 |                      |
 +---------+------------+
           |
           |
           |
           v
+----------+------------+
|   @click.pass_context |
|        worker         |
|                       |
|                       |
|     WorkerCommand     |
| celery/bin/worker.py  |
+-----------------------+

0x07 Worker application

此时在该函数中会实例化app的Worker,Worker application 就是 worker 的实例此时的app就是前面定义的Celery类的实例app

定义在:celery/app/base.py。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@cached_property
def Worker(self):
    """Worker application.

    See Also:
        :class:`~@Worker`.
    """
    return self.subclass_with_self('celery.apps.worker:Worker')

此时subclass_with_self利用了Python的type动态生成类实例的属性。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def subclass_with_self(self, Class, name=None, attribute='app',
                       reverse=None, keep_reduce=False, **kw):
    """Subclass an app-compatible class.
    """
    Class = symbol_by_name(Class)                               # 导入该类
    reverse = reverse if reverse else Class.__name__            # 判断是否传入值,如没有则使用类的名称

    def __reduce__(self):                                       # 定义的方法 该方法在pickle过程中会被调用
        return _unpickle_appattr, (reverse, self.__reduce_args__()) 

    attrs = dict(
        {attribute: self},                                      # 默认设置app的值为self
        __module__=Class.__module__,    
        __doc__=Class.__doc__,
        **kw)                                                   # 填充属性
    if not keep_reduce:                                         
        attrs['__reduce__'] = __reduce__                        # 如果默认则生成的类设置__reduce__方法

    return type(bytes_if_py2(name or Class.__name__), (Class,), attrs) # 利用type实诚类实例

此时就已经从 worker 命令 得到了一个celery.apps.worker:Worker的实例,然后调用该实例的start方法,此时首先分析一下Worker类的实例化的过程。

我们先回顾下:

我们的执行从 worker_main 这个程序入口,来到了 Celery 应用。然后进入了 Celery Command,然后又进入到了 Worker 子Command,具体如下图。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
                                     +----------------------+
      +----------+                   |  @cached_property    |
      |   User   |                   |      Worker          |
      +----+-----+            +--->  |                      |
           |                  |      |                      |
           |  worker_main     |      |  Worker application  |
           |                  |      |  celery/app/base.py  |
           v                  |      +----------------------+
 +---------+------------+     |
 |        Celery        |     |
 |                      |     |
 |  Celery application  |     |
 |  celery/app/base.py  |     |
 |                      |     |
 +---------+------------+     |
           |                  |
           |  celery.main     |
           |                  |
           v                  |
 +---------+------------+     |
 |  @click.pass_context |     |
 |       celery         |     |
 |                      |     |
 |                      |     |
 |    CeleryCommand     |     |
 | celery/bin/celery.py |     |
 |                      |     |
 +---------+------------+     |
           |                  |
           |                  |
           |                  |
           v                  |
+----------+------------+     |
|   @click.pass_context |     |
|        worker         |     |
|                       |     |
|                       |     |
|     WorkerCommand     |     |
| celery/bin/worker.py  |     |
+-----------+-----------+     |
            |                 |
            +-----------------+

下面就会正式进入 worker,Celery 把 worker 的正式逻辑成为 work as a program。

我们在下文将接下来继续看后续 work as a program 的启动过程。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-03-29 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
1 条评论
热度
最新
现在根本找不到这个镜像!
现在根本找不到这个镜像!
回复回复点赞举报
推荐阅读
如何通过Genstat软件来计算遗传力和配合力?
对于不经常编程的小伙伴,Genstat窗口的选择模型,方差分析、混合线性模型、配合力分析、基因与环境互作等功能,特别适合农业方向的数据分析。这个软件功能很强大,通过鼠标点击的形式就可以进行复杂模型的分析,非常666。
邓飞
2024/03/25
6830
如何通过Genstat软件来计算遗传力和配合力?
育种中一般配合力和特殊配合力的计算方法
研究生期间,学习数量遗传学时,对配合力的概念感到很神奇,曾经和同学讨论过,按道理说曹操的一般配合力很高,几个孩子都很出色。
邓飞
2019/12/05
1.7K0
NCII试验 计算配合力和遗传力的方法
育种中,有几个必须要掌握的概念,配合力是其中之一。配合力包括一般配合力和特殊配合力。这个概念很抽象,下面用曹操的例子,解释一下。
邓飞
2022/12/13
4270
NCII试验 计算配合力和遗传力的方法
GS在植物育种中的成本和遗传增益分析
文章的亮点是基因组选择在植物育种中的优势分析, 从时间成本, 金钱成本, 效益成本进行分析, 今天看来还是有很强的参考性.
邓飞
2019/06/13
1.3K0
如何使用NC II 遗传设计估算配合力和遗传力?
非常令人疑惑,于是我就多看了一些教材,发现是有一个万能公式的,即是考虑近交系数,整体结论:
邓飞
2020/08/24
1.6K0
如何使用NC II 遗传设计估算配合力和遗传力?
如何计算配合力+方差组分+遗传力
育种中,有几个必须要掌握的概念,配合力是其中之一。配合力包括一般配合力和特殊配合力。这个概念很抽象,下面用曹操的例子,解释一下。
邓飞
2022/12/13
6920
如何计算配合力+方差组分+遗传力
我的农学转数据分析之花花草草
数据分析界育种知识最好、育种界编程最扎实、段子讲得最好的数据分析师,所以:编程+数据分析+育种,就是我的日常工作了。
邓飞
2022/12/12
5650
我的农学转数据分析之花花草草
通过基因组选择预测杂交水稻的表现(数据挖掘)
基因组选择,预测杂种优势,在水稻可以用,在玉米,高粱中也可以用,在动物选择配套系时也可以用,根据加性效应和非加性效应进行预测,前景广阔。
邓飞
2019/06/13
1K0
GLMM:广义线性混合模型(遗传参数评估)
这篇文章,主要是介绍了抗性数据,如何利用GLMM模型进行的分析,文中,他将9级分类性状变为了二分类性状,进行分析。
邓飞
2020/09/30
2.2K0
GLMM:广义线性混合模型(遗传参数评估)
全同胞家系如何计算遗传力及育种值
大家好,我是飞哥,今天是农历七月初七,中国的情人节,祝大家节日快乐,有情人终成眷属,单身的尽快脱单。
邓飞
2022/12/13
8490
全同胞家系如何计算遗传力及育种值
当我们在说方差分析时,我们在说些什么?
方差分析或变方分析(Analysis of variance,简称ANOVA)为数据分析中常见的统计模型,主要为探讨连续型(Continuous)资料型态之因变量(Dependent variable)与类别型资料型态之自变量(Independent variable)的关系,当自变项的因子中包含等于或超过三个类别情况下,检定其各类别间平均数是否相等的统计模式,广义上可将T检定中方差相等(Equality of variance)的合并T检定(Pooled T-test)视为是方差分析的一种,基于T检定为分析两组平均数是否相等,并且采用相同的计算概念,而实际上当方差分析套用在合并T检定的分析上时,产生的F值则会等于T检定的平方项。
邓飞
2019/09/25
1.6K0
当我们在说方差分析时,我们在说些什么?
文献阅读: 林木中遗传参数评估
这篇文章, 非常具有代表性, 可以为林木和作物的数据分析提供思路, 不一定非要有系谱才可以计算育种值和遗传相关, 混合线性模型代替一般线性模型进行育种值的筛选, 是大势所趋, 必须推而广之.
邓飞
2019/06/13
6620
统计遗传学:第二章,统计分析概念
前几天推荐了这本书,可以领取pdf和配套数据代码。这里,我将各个章节介绍一下,总结也是学习的过程。
邓飞
2022/07/27
8000
统计遗传学:第二章,统计分析概念
环境遗传相关 | 育种中的基因与环境互作
基因与环境互作,植物中同一个品种多年多点种植,评价基因与环境互作,找到品种最适合推广的区域。
邓飞
2022/12/13
1.1K0
环境遗传相关 | 育种中的基因与环境互作
完结篇 | GWAS计算BLUE值4--联合方差分析演示
本篇,用书籍中的数据和结论,用R语言的一般线性模型和混合线性模型,做一下一年多点的联合方差分析的演示。
邓飞
2021/12/20
8110
完结篇 | GWAS计算BLUE值4--联合方差分析演示
多年多点数据如何计算遗传力以及BLUP值
之前写过一篇博客, 介绍领导安利我哔哩哔哩的故事, 介绍到我将我从YouTube上收集的关于混合线性模型, 关于GWAS, 关于GS, 关于农业数据分析相关的视频, 上传到了哔哩哔哩上面. 今天我们看一下介绍多年多点遗传力及BLUP值计算的视频内容. 阅读原文可以查看视频, 这里我用文字和代码进行重演.
邓飞
2019/06/13
4.9K1
GWAS计算BLUE值3--LMM考虑残差异质计算BLUE值
本节,介绍如何使用R语言的asreml包拟合混合线性模型,定义残差异质,计算最佳线性无偏估计(blue)
邓飞
2021/12/20
8960
GWAS计算BLUE值3--LMM考虑残差异质计算BLUE值
动物育种统计发展的百年--翻译版
Daniel Gianola1–5 and Guilherme J.M. Rosa1,2
邓飞
2023/09/06
4040
动物育种统计发展的百年--翻译版
农学的为何要学习神经网络???
在我刚开始学习GS的时候,我是从混合线性模型(LMM)的基础上理解的,因为动物模型BLUP,所以基因组选择GBLUP,再所以一步法ssGBLUP。
邓飞
2022/12/13
3430
农学的为何要学习神经网络???
MP长篇综述 | 植物泛基因组及其应用
2022年12月15日,中山大学史俊鹏副教授、中国科学院遗传与发育生物学研究所田志喜研究员、中国农业大学赖锦盛教授和上海师范大学黄学辉教授共同撰文,在Molecular Plant杂志发表了题为“Plant pan-genomics and its applications”的长篇综述。该论文对植物中泛基因组产生的源动力、表征、分析方法以及在植物遗传学和育种中的应用进行了系统总结和展望。
生信宝典
2023/08/30
6920
MP长篇综述 | 植物泛基因组及其应用
推荐阅读
相关推荐
如何通过Genstat软件来计算遗传力和配合力?
更多 >
LV.2
深圳市星速云网络科技有限公司系统运维
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档