Tag: 硬件

  • 如何使用Weights & Biases Weave监控OpenAI API调用

    如何使用Weights & Biases Weave监控OpenAI API调用

    在数字化时代,人工智能和深度学习技术正迅速发展,而OpenAI一直是这一领域的领先者之一。但是,随着项目和团队的增长,对OpenAI API的使用情况的监控变得越来越重要。本教程将向您展示如何使用Weights & Biases Weave来监控OpenAI API调用,了解项目和团队如何使用语言模型(LLMs),并可视化这些数据以便更好地管理您的项目。

    开篇故事

    想象一下,您正在领导一个人工智能团队,团队成员在多个项目中使用OpenAI的语言模型。您关心的不仅是项目的进展,还包括如何优化API调用、控制成本、降低延迟和提高吞吐量。然而,要了解这些关键指标,需要大量的数据和分析工作。这时,Weights & Biases Weave登场了。它为您提供了一个强大的工具,可以自动跟踪LLM的使用情况,记录有关成本、延迟和吞吐量的关键指标,并为您提供交互式的仪表板,以便更轻松地与团队共享进展。

    步骤0:设置

    在开始之前,您需要进行一些设置。首先,安装所需的依赖项,然后登录到Weights & Biases(W&B)以保存和分享您的工作,并与OpenAI进行身份验证。

    # 如果尚未安装
    !pip install -qqq weave openai tiktoken wandb
    
    import wandb
    wandb.login()
    
    import weave
    import os
    WANDB_BASE_URL = "https://api.wandb.ai"
    os.environ["WANDB_BASE_URL"] = WANDB_BASE_URL
    
    # 与OpenAI进行身份验证
    from getpass import getpass
    
    if os.getenv("OPENAI_API_KEY") is None:
      os.environ["OPENAI_API_KEY"] = getpass("从 https://platform.openai.com/account/api-keys 复制粘贴您的OpenAI密钥\n")
    assert os.getenv("OPENAI_API_KEY", "").startswith("sk-"), "这似乎不是一个有效的OpenAI API密钥"
    print("OpenAI API密钥已配置")

    步骤1:配置数据流和存储在W&B中

    在W&B中,您需要配置数据流和存储,以便记录OpenAI API调用的日志。设置WB_ENTITY为您的W&B用户名或团队名称,WB_PROJECT为项目名称,STREAM_NAME为记录表的名称。

    WB_ENTITY = # 设置为您的W&B用户名或团队名称
    WB_PROJECT = "weave"  # 为此工作创建顶级目录
    STREAM_NAME = "openai_logs"  # 记录表,用于存储OpenAI API调用的日志

    步骤2:调用init_monitor()

    要开始监控OpenAI API的使用情况,请调用init_monitor(<stream>),其中<stream>的格式为<wandb_team_or_user>/<wandb_project>/<stream_name>。该流会记录并存储所有OpenAI API调用的日志。

    from weave.monitoring import openai, init_monitor
    m = init_monitor(f"{WB_ENTITY}/{WB_PROJECT}/{STREAM_NAME}")
    
    # 为简单起见,指定一个模型
    OPENAI_MODEL = 'gpt-3.5-turbo'
    
    # 使用一些示例日志进行预填充
    r = openai.ChatCompletion.create(model=OPENAI_MODEL, messages=[{"role": "user", "content": "hello world!"}])
    r = openai.ChatCompletion.create(model=OPENAI_MODEL, messages=[{"role": "user", "content": "what is 2+2?"}])

    步骤3:预览监控仪表板

    点击上面的链接预览数据流,然后在右侧边栏中点击“OpenAI Monitor Board”以为此数据流创建Weave Board。

    步骤4:探索和了解您的LLM使用情况

    要保存您的工作,请单击页面顶部的自动生成名称以重命名面板。要分享您的面板,请单击右上角的“发布”。

    通过以下方式,您可以实时可视化您的工作:

    • 将面板保持在单独的选项卡中,并刷新以查看最新数据。
    • 随时重命名面板以更容易参考,并“发布”该版本以与他人共享链接。
    • 通过从weave.wandb.ai导航到相关的W&B实体和W&B项目名称,找到以前保存的面板。
    • 或者打开一个新的面板模板的实例,以从迄今为止积累的所有数据开始。

    接下来,我们将举例说明一些您可以跟踪OpenAI API调用的方式。根据您的用例,还有许多其他可能性,我们迫不及待地期待您从这些起始模板中创建的内容。

    示例

    示例0:记录提示及其完成

    监视ChatCompletion请求并打印相应的响应,仅提取完成的文本。

    response = openai.ChatCompletion.create(model=OPENAI_MODEL, messages=[
            {"role": "user", "content": f"生命、宇宙和一切的意义是什么?"},
        ])
    print(response['choices'][0]['message']['content'])

    示例1:将相关参数作为属性进行跟踪

    将感兴趣的参数分解并将其作为日志记录的属性进行跟踪。在这里,我们将“系统提示”与“提示模板”和“方程”参数分开跟踪。这次我们将打印ChatCompletion调用的完整结构化响应。

    system_prompt = "你总是写成要点"
    prompt_template = '逐步解决以下方程:{equation}'
    params = {'equation': '4 * (3 - 1)'}
    openai.ChatCompletion.create(model=OPENAI_MODEL,
                                 messages=[
                                        {"role": "system", "content": system_prompt},
                                        {"role": "user", "content": prompt_template.format(**params)},
                                    ],
                                 # 您可以在日志记录中添加其他属性
                                 # 有关更多示例,请参见monitor_api笔记本
                                 monitor_attributes={
                                     'system_prompt': system_prompt,
                                     'prompt_template': prompt_template,
                                     'params': params
                                 })

    示例2:记录一系列消息的实时流

    监视消息流并将结果记录为单个记录。请注意:此格式不计算标记数。

    from weave.monitoring.openai import message_from_stream
    r = openai.ChatCompletion.create(model=OPENAI_MODEL, messages=[
            {"role": "system", "content": "你是一个机器人,只说像机器人一样的话,比如滴滴滴。"},
            {"role": "user", "content": "给我讲一个50字的故事。"},
        ], stream=True)
    for s in message_from_stream(r):
        print(s, end='')

    示例3:结构化提示工程实验

    在这里,我们比较了一些系统提示、用户问题和目标受众的玩具选项。尝试您自己的实验,看看在探索Board并按不同参数分组时是否会出现有趣的见解。

    def explain_math(system_prompt, prompt_template, params):
        openai.ChatCompletion.create(model=OPENAI_MODEL,
                                 messages=[
                                        {"role": "system", "content": system_prompt},
                                        {"role": "user", "content": prompt_template.format(**params)},
                                    ],
                                 # 您可以在日志记录中添加其他属性
                                 # 有关更多示例,请参见monitor_api笔记本
                                 monitor_attributes={
                                     'system_prompt': system_prompt,
                                     'prompt_template': prompt_template,
                                     'params': params
                                 })
    
    # 随时替换您自己的提示 :)
    system_prompts = ["你写得非常花哨和诗意", "你非常直接和准确", "平衡简洁和见解"]
    prompt_template = '解释以下方程的解给{audience}听:{equation}'
    equations = ['x^2 + 4x + 9 = 0', '15 * (2 - 6) / 4']
    audience = ["新生", "数学天才"]
    
    for system_prompt in system_prompts:
        for equation in equations:
            for person in audience:
                params = {"equation" : equation, "audience" : person}
                explain_math(system_prompt, prompt_template, params)

    总结

    通过Weights & Biases Weave,您可以轻松监控OpenAI API的使用情况,了解项目和团队如何使用LLMs,并可视化这些数据以便更好地管理您的项目。这种实时监控和数据分析工具将有助于您更好地掌握AI项目的进展,优化API调用,并降低成本。

    希望这个教程对您有所帮助,让您更好地利用Weights & Biases Weave来管理和优化您的OpenAI API项目。如果您有任何问题或需要进一步的帮助,请随时联系我们。

  • 如何使用搜索API和重新排序来进行问题回答

    如何使用搜索API和重新排序来进行问题回答

    有时候,寻找相关信息就像大海捞针一样困难,但不要绝望,GPT可以为我们做很多工作。在本指南中,我们将探讨一种使用各种人工智能技术增强现有搜索系统的方法,帮助我们筛选信息中的噪音。

    GPT检索信息的两种方式如下:

    1. 模仿人类浏览:GPT触发搜索,评估结果,如果必要的话,修改搜索查询。它还可以跟踪特定的搜索结果,形成思维链,就像人类用户会做的那样。
    2. 使用嵌入进行检索:为你的内容和用户查询计算嵌入,然后根据余弦相似度测量选择与用户查询最相关的内容。这种技术在像Google这样的搜索引擎中被广泛使用。

    这两种方法都有潜力,但各自都有缺点:第一种方法由于其迭代性质可能较慢,第二种方法需要预先嵌入整个知识库,不断嵌入新内容并维护矢量数据库。

    通过结合这些方法,并从重新排序方法中汲取灵感,我们找到了一种介于两者之间的方法。这种方法可以在任何现有搜索系统的基础上实施,如Slack搜索API或带有私有数据的内部ElasticSearch实例。它的工作原理如下:

    步骤1:搜索

    1. 用户提出问题。
    2. GPT生成一组潜在的查询。
    3. 并行执行搜索查询。

    步骤2:重新排序

    1. 使用每个结果的嵌入来计算与生成的假设理想答案对用户问题的语义相似性。
    2. 根据此相似性度量对结果进行排序和过滤。

    步骤3:回答

    1. 针对前几名搜索结果,模型生成回答用户问题的答案,包括引用和链接。

    这种混合方法提供了相对较低的延迟,并且可以集成到任何现有的搜索端点中,而无需维护矢量数据库。下面让我们深入了解吧!我们将以News API作为示例领域进行搜索。

    设置

    除了你的OPENAI_API_KEY,你还需要在环境中包含一个NEWS_API_KEY。你可以在这里获取API密钥。

    %env NEWS_API_KEY = YOUR_NEWS_API_KEY
    
    # 依赖项
    from datetime import date, timedelta  # 用于获取最近新闻的日期处理
    from IPython import display  # 用于漂亮的打印
    import json  # 用于解析JSON API响应和模型输出
    from numpy import dot  # 用于余弦相似度
    import openai  # 用于使用GPT和获取嵌入
    import os  # 用于加载环境变量
    import requests  # 用于进行API请求
    from tqdm.notebook import tqdm  # 用于显示进度条

    以上是初始化所需的依赖项和环境变量设置。接下来,我们将逐步执行三个主要步骤:搜索、重新排序和回答。

    步骤1:搜索

    一切都始于用户的问题。首先,用户提出一个问题,然后我们使用GPT生成一系列多样化的查询,以尽可能详尽的方式回答问题。

    # 用户提出问题
    USER_QUESTION = "谁赢得了NBA总冠军?最有价值球员是谁?告诉我一些关于最后一场比赛的情况。"
    
    # 为了尽可能详尽,我们使用模型生成基于此问题的各种查询。
    QUERIES_INPUT = f"""
    你有访问一个返回最近新闻文章的搜索API。
    生成一个与这个问题相关的搜索查询数组。
    为查询使用相关关键字的变体,尽量做到通用。
    包括尽可能多的查询,包括和不包括术语。
    例如,包括像['关键词1 关键词2','关键词1','关键词2']这样的查询。
    要有创造性。包括的查询越多,找到相关结果的可能性就越大。
    
    用户问题: {USER_QUESTION}
    
    格式: {{"queries": ["query_1", "query_2", "query_3"]}}
    """
    
    queries = json_gpt(QUERIES_INPUT)["queries"]
    
    # 让我们也包括原始问题以确保全面。
    queries.append(USER_QUESTION)
    
    queries

    以上代码生成了一系列搜索查询,这些查询包括与用户问题相关的多个关键字和变体。这些查询将在接下来的搜索步骤中用于检索新闻文章。

    接下来,让我们运行这些搜索查询以获取新闻文章。

    def search_news(
        query: str,
        news_api_key: str = news_api_key,
        num_articles: int = 50,
        from_datetime: str = "2023-06-01",  # 2023年NBA总决赛于2023年6月举行
        to_datetime: str = "2023-06-30",
    ) -> dict:
        response = requests.get(
            "https://newsapi.org/v2/everything",
            params={
                "q": query,
                "apiKey": news_api_key,
                "pageSize": num_articles,
                "sortBy": "relevancy",
                "from": from_datetime,
                "to": to_datetime,
            },
        )
    
        return response.json()
    
    articles = []
    
    for query in tqdm(queries):
        result = search_news(query)
        if result["status"] == "ok":
            articles = articles + result["articles"]
    
        else:
            raise Exception(result["message"])
    
    # 移除重复文章
    articles = list({article["url"]: article for article in articles}.values())
    
    print("文章总数:", len(articles))
    print("查询1的前5篇文章:", "\n")
    
    for article in articles[0:5]:
        print("标题:", article["title"])
        print("描述:", article["description"])
        print("内容:", article["content"][0:100] + "...")
        print()

    以上代码执行了搜索查询并获取了与这些查询相关的新闻文章。注意,为了减少重复,我们在获取文章后删除了重复的文章。

    现在,我们已经获得了新闻文章,但很多时候搜索查询会返回大量结果,其中许多与用户最初提出的问题无关。为了提高最终答案的质量,我们将使用嵌入来重新排序和过滤结果。

    步骤2:重新排序

    受HyDE(Gao等人)启发,我们首先生成一个假设理想答案,用于对比和重新排列我们的结果。这有助于优先考虑看起来是好答案的结果,而不是与我们的问题类似的结果。下面是我们用来生成假设答案的提示。

    HA_INPUT = f"""
    生成一个假设的答案,以回答用户的问题。这个答案将用于排名搜索结果。
    假装你拥有回答所需的所有信息,但不要使用任何实际的事实。而是使用占位符
    比如,NAME在某地做了某事,或者NAME在某地说了某话。
    
    用户问题: {USER_QUESTION}
    
    格式: {{"hypotheticalAnswer": "假设答案文本"}}
    """
    
    hypothetical_answer = json_gpt(HA_INPUT)["hypotheticalAnswer"]
    
    hypothetical_answer

    以上代码生成了一个假设答案,这个答案包含了关于NBA总决赛的信息,但没有使用实际的事实,而是使用了占位符。接下来,我们将为搜索结果和假设答案生成嵌入,然后计算这些嵌入之间的余弦距离,得到语义相似性度量。请注意,由于OpenAI嵌入在API中返回时已经归一化,我们可以简单地计算点积来代替进行完整的余弦相似性计算。

    hypothetical_answer_embedding = embeddings(hypothetical_answer)[0]
    article_embeddings = embeddings(
        [
            f"{article['title']} {article['description']} {article['content'][0:100]}"
            for article in articles
        ]
    )
    
    # 计算余弦相似度
    cosine_similarities = []
    for article_embedding in article_embeddings:
        cosine_similarities.append(dot(hypothetical_answer_embedding, article_embedding))
    
    cosine_similarities[0:10]

    以上代码计算了假设答案与每篇文章的嵌入之间的余弦相似性。这些相似性分数将用于对结果进行排序和过滤。

    最后,我们使用这些相似性分数对结果进行排序和过滤。

    scored_articles = zip(articles, cosine_similarities)
    
    # 根据余弦相似度对文章进行排序
    sorted_articles = sorted(scored_articles, key=lambda x: x[1], reverse=True)
    
    # 打印前5篇文章
    print("前5篇文章:", "\n")
    
    for article, score in sorted_articles[0:5]:
        print("标题:", article["title"])
        print("描述:", article["description"])
        print("内容:", article["content"][0:100] + "...")
        print("分数:", score)
        print()

    以上代码对文章进行了排序,按照与假设答案的语义相似性得分降序排列。这些排序后的文章看起来与我们最初的查询更相关。现在,让我们使用前5个结果生成最终答案。

    步骤3:回答

    formatted_top_results = [
        {
            "title": article["title"],
            "description": article["description"],
            "url": article["url"],
        }
        for article, _score in sorted_articles[0:5]
    ]
    
    ANSWER_INPUT = f"""
    根据给定的搜索结果为用户的问题生成答案。 
    顶部结果: {formatted_top_results}
    用户问题: {USER_QUESTION}
    
    在答案中包括尽可能多的信息。引用相关的搜索结果URL作为Markdown链接。
    """
    
    completion = openai.ChatCompletion.create(
        model=GPT_MODEL,
        messages=[{"role": "user", "content": ANSWER_INPUT}],
        temperature=0.5,
        stream=True,
    )
    
    text = ""
    for chunk in completion:
        text += chunk.choices[0].delta.get("content", "")
        display.clear_output(wait=True)
        display.display(display.Markdown(text))

    以上代码使用前5个搜索结果生成了最终的答案,其中包括引用了相关搜索结果的链接。

    至此,我们已经完成了搜索、重新排序和回答的所有步骤。下面,让我们根据以上内容编写一篇优秀的教程文章,满足指定的要求。

    如何使用搜索API和重新排序进行问题回答

    开篇故事

    搜索相关信息有时候就像在庞大的信息海洋中寻找一根针一样困难。但不要担心,人工智能技术可以帮助我们在这个任务中取得很大进展。在本文中,我们将探讨一种方法,利用搜索API和嵌入技术,以及重新排序方法,来实现更准确的问题回答。

    故事开始于一个充满好奇心的用户,他有一个问题:谁赢得了NBA总冠军?最有价值球员是谁?告诉我一些关于最后一场比赛的情况。这个问题看似简单,但

    要从海量的新闻文章中找到相关的信息可能会让人望而却步。

    步骤1:搜索

    首先,用户提出了一个问题。这个问题是我们开始寻找答案的出发点。但为了尽可能全面地查找相关信息,我们使用人工智能模型生成了多个不同的查询,这些查询都与用户的问题相关。这些查询包括谁赢得了NBA总冠军、NBA总决赛的MVP是谁,以及最后一场比赛的概述等等。这些查询一起被发送到搜索API中,以并行方式执行搜索。

    步骤2:重新排序

    一旦我们获得了搜索结果,接下来的步骤是对这些结果进行重新排序。这一步骤受到了HyDE(Gao等人)的启发。我们首先生成了一个假设的理想答案,该答案包含了关于NBA总决赛的信息,但没有使用任何实际的事实,而是使用了占位符。然后,我们为搜索结果和假设答案生成了嵌入,这些嵌入可以帮助我们度量它们之间的语义相似性。最终,我们使用语义相似性分数对结果进行排序,以找出最相关的答案。

    步骤3:回答

    最后,我们使用排名最高的搜索结果生成最终的答案。这个答案包括了与NBA总决赛有关的信息,并引用了相关搜索结果的链接,以便用户可以深入了解。

    通过这个混合方法,我们能够在相对低的延迟下获得高质量的答案,而无需维护一个向量数据库。这种方法可以集成到任何现有的搜索系统中,无论是Slack搜索API还是具有私有数据的内部ElasticSearch实例。

    希望本文对你理解如何使用搜索API和重新排序来回答问题有所帮助!

  • 如何使用tiktoken计算文本中的标记数

    如何使用tiktoken计算文本中的标记数

    在现代自然语言处理中,标记是一种重要的概念,因为它们是语言模型处理文本的基本单元。本教程将向您展示如何使用OpenAI开源的快速分词工具tiktoken来计算文本中的标记数。通过了解文本中有多少标记,您可以:

    1. 判断文本是否太长以至于超出模型处理的限制。
    2. 了解使用OpenAI API调用的成本,因为计费是按标记计算的。

    1. 引言故事

    假设您是一名程序员,正在为自己的聊天应用项目编写代码。您已经集成了一个强大的自然语言处理模型,但现在需要确定用户输入的文本有多少标记,以便确保不会超出模型的限制。在解决这个问题之前,您曾不止一次被意想不到的文本长度问题困扰。一天,您在互联网上发现了一个名为tiktoken的开源工具,它能够快速准确地计算文本中的标记数。这似乎是您解决问题的完美工具,因此您决定深入了解它并开始使用它来解决您的标记计数问题。

    2. 安装tiktoken

    首先,您需要安装tiktoken工具。您可以使用pip来安装它:

    pip install --upgrade tiktoken

    安装完成后,您就可以开始使用tiktoken来计算文本中的标记数了。

    3. 导入tiktoken

    在您的Python项目中,首先导入tiktoken库:

    import tiktoken

    4. 加载编码

    接下来,您需要加载一个编码,以告诉tiktoken如何将文本转换为标记。不同的模型使用不同的编码。在本示例中,我们使用了“cl100k_base”编码,它适用于一些OpenAI模型,包括gpt-4和gpt-3.5-turbo。您可以这样加载编码:

    encoding = tiktoken.get_encoding("cl100k_base")

    5. 使用编码.encode()方法将文本转换为标记

    现在,您可以使用编码对象的.encode()方法将文本转换为标记。该方法将文本字符串转换为标记的整数列表。例如,如果我们有文本字符串”tiktoken is great!”,您可以这样做:

    tokens = encoding.encode("tiktoken is great!")

    这将返回一个整数列表,代表文本中的标记。在这个示例中,返回的标记列表为[83, 1609, 5963, 374, 2294, 0]。

    要计算文本中的标记数,只需查看标记列表的长度:

    num_tokens = len(tokens)

    这将给您文本中的标记数,本例中为6个标记。

    6. 使用编码.decode()方法将标记转换回文本

    如果您需要将标记转换回文本,可以使用编码对象的.decode()方法。例如,如果我们有标记列表[83, 1609, 5963, 374, 2294, 0],您可以这样做:

    text = encoding.decode([83, 1609, 5963, 374, 2294, 0])

    这将返回文本字符串”tiktoken is great!”。

    请注意,虽然.decode()方法可以应用于单个标记,但对于不在utf-8边界上的标记,它可能会导致信息丢失。对于单个标记,.decode_single_token_bytes()方法可以安全地将单个整数标记转换为其表示的字节。

    7. 比较不同编码

    不同编码在分割单词、分组空格和处理非英文字符方面有所不同。使用上述方法,我们可以比较不同编码在几个示例字符串上的效果。以下是一个比较不同编码的函数示例:

    def compare_encodings(example_string: str) -> None:
        """打印三种字符串编码的比较结果。"""
        # 打印示例字符串
        print(f'\n示例字符串: "{example_string}"')
        # 对于每个编码,打印标记数、标记整数和标记字节
        for encoding_name in ["r50k_base", "p50k_base", "cl100k_base"]:
            encoding = tiktoken.get_encoding(encoding_name)
            token_integers = encoding.encode(example_string)
            num_tokens = len(token_integers)
            token_bytes = [encoding.decode_single_token_bytes(token) for token in token_integers]
            print()
            print(f"{encoding_name}: {num_tokens} 个标记")
            print(f"标记整数: {token_integers}")
            print(f"标记字节: {token_bytes}")
    
    compare_encodings("antidisestablishmentarianism")

    8. 为聊天完成API调用计算标记数

    对于像gpt-3.5-turbo和gpt-4这样的ChatGPT模型,它们使用标记方式与较早的完成模型相同,但由于它们基于消息格式,因此更难计算消息将使用多少标记。

    以下是一个用于计算传递给gpt-3.5-turbo或gpt-4的消息标记数的示例函数。请注意,从消息中计算标记的方式可能会因模型而异。考虑到下面的函数中计算的标记数量是一个估计值,而不是一个永恒的保证。

    def num_tokens_from_messages(messages, model="gpt-3.5-turbo-0613"):
        """返回消息列表使用的标记数。"""
        try:
            encoding
    
     = tiktoken.get_encoding(model)
        except Exception as e:
            print(f"获取编码时发生错误:{e}")
            return None
    
        total_tokens = 0
        for message in messages:
            tokens = encoding.encode(message["content"])
            num_tokens = len(tokens)
            # 添加额外的标记以表示用户或系统角色
            if message["role"] == "system":
                num_tokens += 1
            else:
                num_tokens += 2  # 一个用于角色,一个用于分隔符
            total_tokens += num_tokens
    
        return total_tokens
    
    # 示例消息列表
    messages = [
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Tell me a joke."},
        {"role": "assistant", "content": "Why did the chicken cross the road?"},
        {"role": "user", "content": "I don't know, why did the chicken cross the road?"}
    ]
    
    total_tokens = num_tokens_from_messages(messages, model="gpt-3.5-turbo-0613")
    print(f"消息列表中的总标记数:{total_tokens}")

    这个函数可以帮助您估算给定消息列表的标记数,以便控制文本长度和计费。请注意,不同模型的标记数限制可能会有所不同,因此在实际使用中请谨慎估算。

  • 如何使用PHP获取本机IPv4和IPv6地址

    如何使用PHP获取本机IPv4和IPv6地址

    在这个高度互联的时代,我们对于网络连接的依赖无处不在。无论是在服务器上运行网站,还是在树莓派上搭建物联网项目,获取本机的IPv4和IPv6地址都是至关重要的。这些地址是我们设备与互联网交流的通道,也是实现各种网络功能的基础。在这篇文章中,我们将探讨如何使用PHP编程语言获取本机的IPv4和IPv6地址,以便更好地管理网络连接和实现各种应用。

    步骤一:了解IPv4和IPv6的区别

    IPv4和IPv6都是用于标识网络上设备的地址协议,但它们有一些重要的区别。IPv4采用32位地址,而IPv6采用128位地址。IPv4地址已经枯竭,而IPv6地址则更为充足。在开始获取本机地址之前,了解这些基本知识对于正确选择适当的地址协议至关重要。

    步骤二:使用PHP编写获取IPv4地址的代码

    首先,我们将探讨如何使用PHP编写代码来获取本机的IPv4地址。PHP提供了一些内置函数和变量,可以轻松实现这一目标。以下是一个简单的示例:

    <?php
    $ipv4 = gethostbyname(gethostname());
    echo "本机IPv4地址是:" . $ipv4;
    ?>

    这段代码中,我们使用了gethostbyname()函数来获取主机名对应的IPv4地址,并将结果打印出来。这是一个简单而有效的方法来获取本机的IPv4地址。

    步骤三:使用PHP编写获取IPv6地址的代码

    如果你的网络环境支持IPv6,并且你需要获取IPv6地址,那么我们也可以使用PHP编写相应的代码。以下是一个示例:

    <?php
    $ipv6 = gethostbyname("ipv6.google.com");
    echo "本机IPv6地址是:" . $ipv6;
    ?>

    这段代码中,我们使用gethostbyname()函数来获取ipv6.google.com的IPv6地址。这个地址通常是本机的IPv6地址之一。请注意,获取IPv6地址可能需要确保网络环境已经启用了IPv6支持。

    步骤四:处理异常情况

    在获取IPv4和IPv6地址时,可能会遇到一些异常情况,例如网络连接断开或无法解析主机名。为了确保代码的稳定性,我们可以使用异常处理机制来捕获并处理这些异常。以下是一个简单的异常处理示例:

    <?php
    try {
        $ipv4 = gethostbyname(gethostname());
        echo "本机IPv4地址是:" . $ipv4;
    } catch (Exception $e) {
        echo "无法获取IPv4地址:" . $e->getMessage();
    }
    
    try {
        $ipv6 = gethostbyname("ipv6.google.com");
        echo "本机IPv6地址是:" . $ipv6;
    } catch (Exception $e) {
        echo "无法获取IPv6地址:" . $e->getMessage();
    }
    ?>

    这段代码中,我们使用try和catch块来捕获可能发生的异常,并提供相应的错误消息。

    步骤五:完善和优化代码

    获取本机的IPv4和IPv6地址只是一个简单的示例。在实际应用中,你可能需要更多的错误处理、地址验证和网络连接管理。此外,你还可以考虑将获取地址的功能封装成一个函数,以便在不同的项目中重复使用。

    结论

    获取本机的IPv4和IPv6地址是网络编程中的一个基本任务。使用PHP编程语言,我们可以轻松实现这一目标,无论是在服务器上还是在树莓派等嵌入式设备上。通过了解IPv4和IPv6的区别,编写相应的PHP代码,并进行异常处理,我们可以更好地管理网络连接并实现各种网络应用。

    无论你是一个网络管理员还是一个网络编程爱好者,掌握如何获取本机地址的技能都将为你在网络世界中的冒险提供强大的支持。

  • 制作3D打印和树莓派驱动的ChatGPT机器人教程

    制作3D打印和树莓派驱动的ChatGPT机器人教程

    你是否曾经想过拥有一个能够与你互动的ChatGPT机器人,而且它还拥有可爱的外观?那么,你来对地方了!在这篇教程中,我们将向你展示如何制作一个由3D打印和树莓派驱动的ChatGPT机器人。这个机器人将能够回答你的问题、进行有趣的对话,而且还有一个可爱的外壳,使它看起来像一只机械熊一样。

    步骤1:3D打印机器人外壳和组件

    首先,我们需要制作机器人的外壳和组件。根据Adafruit Learning System提供的指南,你需要打印以下部分:

    • 主机箱: 1 x Case Top.stl,1 x Case Bottom.stl
    • 扬声器固定器: 如果使用4mm 0.25W的扬声器,则需要2 x 4mm Thick Speaker Retainer.stl;如果升级到Adafruit 2mm 0.5W的扬声器,则需要2 x 2mm Thick Speaker Retainer.stl【14†source】.

    确保你的3D打印机和材料准备好,并按照指南的建议进行打印。一旦完成,你将获得一个机器人的基本外壳,接下来,我们将在内部安装树莓派和其他组件。

    步骤2:安装和配置树莓派

    在机器人外壳中安装树莓派是关键的一步。以下是详细的操作指南:

    1. 安装64位的Raspberry Pi OS Lite,因为OpenAI库只能在此版本上安装。
    2. 为音频系统和驱动程序安装额外的库,例如libpulse-dev, pulseaudio, 和 apulse。
    3. 如果安装了MAX98357音频芯片,需要按照指南进行额外的配置【18†source】.

    完成这些步骤后,你的树莓派将准备好用于机器人的音频和控制系统。

    步骤3:编写和运行代码

    现在,让我们来看看在树莓派上运行的代码。这个代码涉及到Azure认知服务、语音识别库和OpenAI库,以及一些用于控制机器人动作的参数设置。你可以从Adafruit Learning System下载项目包,里面包含了完整的代码【22†source】.

    在运行代码之前,请确保你已经按照指南配置好了所需的API密钥和设置。这将确保机器人能够正常运行并进行语音识别和回答问题。

    步骤4:集成ChatGPT

    最后,我们来看看如何集成ChatGPT,使机器人能够进行智能对话。参考Pi My Life Up的指南,了解如何在树莓派上交互使用ChatGPT API【17†source】.

    这个步骤将使你的机器人能够回答各种问题,并进行有趣的对话。你可以根据自己的需求和喜好配置ChatGPT的行为。

    结尾

    通过完成以上步骤,你将拥有一个令人印象深刻的3D打印和树莓派驱动的ChatGPT机器人。你可以为它编写自定义的对话脚本,让它成为你的智能伴侣。

    这个项目不仅是一个有趣的技术挑战,还可以让你学习如何使用树莓派和API来创建强大的人工智能应用程序。希望你享受制作和与你的机器人互动的过程!

  • 从闪电到永恒:深入理解NVMe SSD的原理、协议和寿命

    从闪电到永恒:深入理解NVMe SSD的原理、协议和寿命

    有一天,你坐在电脑前,迫不及待地等待你的电脑启动。但是,你突然意识到,这个过程已经不再是以前那种拖延症患者的游戏了。这一切都要感谢新一代的NVMe SSD(Non-Volatile Memory Express Solid State Drive)。在这篇文章中,我们将深入探讨NVMe SSD的工作原理、协议以及如何延长它们的寿命,以便你更好地了解并发挥其潜力。

    NVMe SSD简介

    NVMe SSD是一种高性能、低延迟的存储设备,它采用了非易失性内存(NVM)作为存储介质。相对于传统的SATA SSD或机械硬盘,NVMe SSD具有更快的读写速度,这意味着你的系统启动速度将得到巨大的提升。

    NVMe SSD的工作原理

    闪存芯片

    NVMe SSD的核心是闪存芯片。这些芯片使用闪存存储数据,而不是传统硬盘上的旋转磁盘。它们由许多存储单元组成,每个存储单元都可以存储一定数量的数据。当你写入或读取数据时,存储单元中的电子状态会发生改变,从而实现数据的存储和检索。

    控制器

    NVMe SSD还包括一个重要的组件,即控制器。控制器充当数据流的管家,确保数据在芯片之间正确流动。它负责处理读取和写入请求,并管理垃圾回收,以确保芯片保持高性能。

    NVMe协议

    NVMe SSD之所以如此迅猛,部分原因在于其使用了一种先进的协议,即NVMe协议。这个协议允许系统与SSD之间进行高效的通信,减少了延迟,提高了性能。它是为固态存储器而设计的,与SATA协议相比,具有更低的通信开销。

    寿命和耐用性

    现在,让我们来谈谈NVMe SSD的寿命。虽然它们非常快速和可靠,但也需要一些关注和维护,以确保其寿命最大化。

    首先,要注意的是NVMe SSD有一个写入寿命。每个存储单元只能写入一定数量的数据,之后就会变得不稳定。这就是为什么需要实现TRIM功能,它有助于垃圾回收并延长SSD的寿命。

    其次,要避免频繁的大容量写入。如果你需要处理大量的数据写入操作,考虑使用定期备份,以减少对SSD的冲击。

    此外,保持系统和固件更新也很重要。制造商通常会发布更新,以提高SSD的性能和耐用性。

    最后,避免高温和高湿度环境,因为这些条件可能会对NVMe SSD产生不利影响。

    结语

    通过了解NVMe SSD的工作原理、协议和寿命,你可以更好地利用这一先进的存储技术,提高你的系统性能,并确保它们的持久性。要记住,定期维护和注意使用方法是确保NVMe SSD长时间高效运行的关键。

  • 从进程池到线程池:实现高效图片下载

    从进程池到线程池:实现高效图片下载

    在数字时代,我们每天都能够轻松访问到各种各样的图片,不论是美景、艺术品还是有趣的表情包。然而,有时候我们需要大量的图片数据,例如用于机器学习的训练集或者简单的个人收藏。在这种情况下,如何高效地获取和保存这些图片就成了一个挑战。今天,我将向大家介绍一种使用进程池和线程池相结合的方法,以实现高效的图片下载。

    准备工作

    首先,让我们明确一下需要的准备工作。我们将使用Python来完成这个任务,所以确保你已经安装了Python环境。此外,我们还需要以下库:

    • requests:用于发送HTTP请求和获取网页内容。
    • lxml:用于解析HTML文档。
    • multiprocessing:用于创建进程池和进程共享变量。
    • concurrent.futures:用于创建线程池。

    确保你已经安装了这些库,如果没有,可以使用pip来安装。

    获取图片地址

    首先,我们需要获取要下载的图片的地址。在这个例子中,我们将从一个网站上抓取动漫壁纸的图片地址。我们使用了requests库来发送GET请求,然后使用lxml来解析HTML文档,提取出图片的地址。这些地址将被放入一个进程队列中,以便后续的下载。

    # 获取图片地址
    def get_url(url, que):
        resp = requests.get(url, headers=headers)
        resp.encoding = resp.apparent_encoding
        date = resp.text
        tree = etree.HTML(date)
        list_url = tree.xpath('//ul[@class="clearfix"]/li/a')
        for i in list_url:
            url_img = i.xpath('./img/@src')
            que.put('https://pic.netbian.com' + str(*url_img))  # put写入进程变量队列中
        resp.close()

    下载并保存图片

    接下来,我们需要编写函数来下载并保存图片。我们使用requests库发送GET请求,然后将图片保存到本地。为了避免文件名冲突,我们可以使用一个共享的数值型变量来为每张图片分配一个唯一的文件名。这个变量会在多个进程之间共享,确保每张图片的文件名都不同。

    # 下载并保存图片
    def download_ove(url, name):
        try:
            resp = requests.get(url, headers=headers)
            path_img = os.path.join(path, f'{name.value}.jpg')
            with open(path_img, 'wb') as f:
                f.write(resp.content)
            print(f'保存成功{name.value}.jpg')
            name.value += 1  # 数值型进程变量自增
        except Exception as ex:
            print('下载出错', ex)

    下载图片的主函数

    现在,让我们来编写下载图片的主函数。我们使用了线程池来并发下载图片,这样可以提高下载速度。通过创建一个ThreadPoolExecutor对象,我们可以指定同时运行的线程数量,这里设置为20。然后,我们从进程队列中获取图片地址,并将下载任务提交给线程池处理。

    # 获取进程队列中的url并启用线程池下载保存图片
    def download_img(que, name):
        # 创建线程池,指定20个线程处理数据
        with ThreadPoolExecutor(20) as t:
            while True:
                try:
                    s = que.get(timeout=3)  # 获取进程队列中的数据,等待3秒若是还没获取到数据抛出异常
                    t.submit(download_ove, s, name)  # 添加进线程池
                except Exception as ec:
                    print(ec)
                    break

    异常处理

    在我们的代码中,我们还加入了异常处理机制。如果下载出现错误,我们会捕获异常并打印出错信息。这有助于我们及时发现问题并进行处理。

    # 接收进程池与线程池异常的回调函数
    def err_call_back(err):
        print(f'出错啦~ error:{str(err)}')

    执行主程序

    最后,我们在主程序中执行上述函数。我们首先创建了一个进程共享的队列变量和一个数值型的共享变量,用于存储图片地址和文件名计数。然后,我们根据需要获取多个页面的图片地址,将下载任务提交给进程池,并等待任务完成。这样,我们就能够高效地下载大量图片了。

    if __name__ == '__main__':
        if not os.path.exists(path):
            os.mkdir(path)
        que = multiprocessing.Manager().Queue()  # 创建一个进程之间共享的队列变量
        name = multiprocessing.Manager().Value('i', 0)  # 创建一个进程之间共享的数值型变量,'i'表示整型数字,0表示从0开始
        for i in range(1, 4):
            if i != 1:
                url = f'https://pic.netbian.com/4kdongman/index_{i}.html'
            else:
                url = 'https://pic.netbian.com/4kdongman/'
            get_url(url, que)
            #  创建进程池,并将函数添加到进程池内,指定最多开辟1个进程处理数据(开多了怕把网址玩崩)
            with multiprocessing.Pool(1) as pool:
                pool.apply(download_img, args=(que, name))  # 将函数以同步的方式添加进进程池
        pool.close()  # 结束进程池,不在往内添加数据
        pool.join()  # 等待进程池运行结束
        print('结束')

    结束语

    通过使用进程池和线程池的组合,我们能够高效地下载大量图片,提高了任务的并发性和效率。这种方法对于需要大规模获取图片数据的任务非常有用,例如构建图像数据集或爬取网站上的图片资源。

    希望这个教程对你有所帮助,如果你有任何问题或建议,欢迎在评论中留言。祝愿你在图片下载任务中取得成功!

  • 如何理解英伟达的CUDA技术:计算领域的革命者

    如何理解英伟达的CUDA技术:计算领域的革命者

    在密尔沃基工学院的演讲中,英伟达的CEO黄仁勋分享了一段令人振奋的话语,他讲述了英伟达的发展史以及一项技术的贡献,这项技术便是CUDA。这个技术已经改变了计算领域的格局,让GPU在大数据计算中崭露头角。那么,CUDA究竟有何魔力,为什么它如此重要呢?

    如何理解英伟达的CUDA技术:计算领域的革命者 如何理解英伟达的CUDA技术:计算领域的革命者

    CUDA:并行计算的魔法

    CPU和GPU都是计算机处理器,它们能够执行各种计算任务,但它们在计算方式上存在差异。CPU擅长线性计算,就像一位大学教授,能够独立解决复杂问题,但步骤逐一进行。而GPU则更像一群小学生,单核计算能力不如CPU,但核心数量众多,能够同时进行计算。

    CUDA技术就是那个调动小学生群体的指挥棒。通过CUDA,研究员和编程人员可以使用编程语言与硬件设备进行交互,将复杂的数学问题分解为多个简单的子问题,并将这些子问题分发给GPU的多个计算核心。正如黄仁勋所言,CUDA成为了科学向前发展的最佳解法,其强大的计算能力使其成为超级计算机的首选。

    CUDA的广泛应用

    自从英伟达于2006年推出CUDA以来,它已经渗透到几乎所有与计算有关的领域。航空航天、生物科学研究、机械和流体模拟、能源探索等各个领域的研究都在CUDA的基础上进行。事实上,80%的计算领域已经被英伟达的CUDA技术所影响。

    而CUDA的生态合作伙伴也在不断壮大。根据英伟达2023财年年报,目前有400万名开发者正在与CUDA合作。在过去的两年半里,这一数字翻了一番,CUDA的下载量已经超过了4000万次。此外,英伟达还推出了CUDA-X AI,这是一组建立在CUDA之上的软件加速库,提供了深度学习、机器学习和高性能计算所需的优化功能,成为了数据科学加速的端到端平台。

    竞争与挑战

    尽管CUDA在计算领域取得了巨大成功,但竞争对手也不甘示弱。AMD推出了生态平台ROCm,同样兼容不少计算框架。OpenAI的Triton被认为是CUDA的有力挑战者。苹果设计的开源构架OpenCL借鉴了CUDA的成功经验,并支持多核CPU、GPU或其他加速器。谷歌通过TPU、TensorFlow和云吸引开发者和客户。

    然而,在实际工作中,这些竞争者面临各种问题。一些开发者表示,虽然理论上支持这些竞争技术,但在实际使用中经常遇到错误和崩溃。

    结语

    CUDA技术的崛起改变了计算领域的格局,使GPU成为了大数据计算的基石。它在科学研究、工程模拟、机器学习等领域发挥着不可替代的作用。尽管竞争者不断涌现,但CUDA的生态系统仍然如日中天,英伟达在这个领域占据着主导地位。

    在未来,我们可以期待CUDA技术继续演化,为计算领域带来更多的创新和进步。

  • 电子游戏发展史:从早期探索到现代娱乐的演变

    电子游戏发展史:从早期探索到现代娱乐的演变

    想象一下,回到20世纪中叶的那个时代,电子游戏还没有像今天这样普及,计算机技术还在蓬勃发展的初期阶段。屏幕上的小点点、简单的图形,正是电子游戏的萌芽期。本文将带你穿越时光,探索早期电子游戏的历史,了解它们是如何从技术演示和学术研究中崭露头角,成为现代文化中不可或缺的一部分的。

    电子游戏发展史:从早期探索到现代娱乐的演变 电子游戏发展史:从早期探索到现代娱乐的演变

    早期电子游戏的踪迹

    早期的电子游戏历史可以追溯到1947年,那时诞生了第一款结合屏幕的交互电子类游戏。这个时期的游戏主要是为了技术演示和学术研究而存在的,比如1950年的《大脑伯蒂》和1951年的Nimrod。研究机构开始开发一系列模拟现实世界棋盘游戏的游戏,以探索编程、人机交互、电脑算法等领域。其中包括了1952年的《OXO》(首款结合阴极射线管显示器的游戏程序),以及数款国际象棋和西洋跳棋程序。这些早期游戏奠定了电子游戏领域的基础,尽管它们在当时仅为少数计算机专家所熟知。

    电子游戏的初露锋芒

    随着计算机技术的不断进步,电脑体积变得越来越小,运算速度亦越来越快。到了20世纪50年代末,大学学生和员工都可以使用电脑进行工作。这一时期,一群热衷于编程的程序员开始利用电脑编写与学术无直接关系的程序,其中包括了一款里程碑式的游戏,《太空战争!》,它于1962年推出。这款游戏成为了首款可以在单一机构以外接触到的电子游戏,标志着电子游戏的娱乐时代的开启。

    电子游戏发展史:从早期探索到现代娱乐的演变 电子游戏发展史:从早期探索到现代娱乐的演变

    电子游戏的蓬勃发展

    随着60年代的到来,越来越多的程序员开始开发数字电脑游戏,它们有时甚至出现在程序目录内,供商品销售。电脑成本逐渐下降,电子游戏的受众扩大至数十个研究机构,同时不同编程语言的出现有利于开发更多种类的游戏。70年代初,伴随着投币式街机游戏《银河游戏》原型机的亮相,以及《电脑太空战》和《乓》等游戏的登场,商业电子游戏产业正式成形。与此同时,1972年家用电子游戏机米罗华奥德赛的推出,为第一世代游戏机的诞生打开了序幕,为家庭娱乐带来了全新的可能性。

    电子游戏的技术定义

    早期的电子游戏是如何定义的呢?从技术上讲,一个产品只有向显示器发送视频信号,才能被称为电子游戏。这个显示器可以是阴极射线管、示波器、液晶显示器等。然而,这个定义并不包括早期的电脑游戏,因为它们通常将结果输出到打印机或电传打字机,而不是显示器上。这个术语的演变反映了技术的发展,从最初的硬件依赖性到更广泛的娱乐概念。

    电子游戏的更广泛定义

    随着时间的推移,电子游戏的定义已经变得更加广泛。现在,电子游戏不再仅仅依赖于硬件,它们包括任何在具有电子逻辑电路的硬件上进行的游戏,具有交互元素,并将玩家行动的结果输出到显示器上。这个更广泛的定义使得电子游戏可以涵盖多种形式,从早期的实验项目到今天的主流娱乐。

    电子游戏的早期探索

    早期的电子游戏起源于20世纪50年代初,它们通常与大学和大公司的研究项目相关。这些早期游戏往往是为了设备宣传或学术研究而存在的,而不是娱乐用途。然而,它们为电子游戏的未来奠定了基础,尤其是那些使用阴极射线管屏幕的设备。

    阴极射线管娱乐设备的诞生

    最早的交互电子类游戏之一是阴极射线管娱乐设备。它是已知最早的电子游戏,于1947年注册专利。该设备包括一个连接到示波器的阴极射线管,以及一组旋钮和开关,玩家需要利用旋钮来调整投射点的运动轨道,尝试击中覆盖在显示器上的塑胶目标。尽管这个设备仅基于模拟电路,没有使用数字计算机或程序,但它被认为是电子游戏的先驱之一。

    电子游戏的不断发展

    随着时间的推移,电子游戏不断发展壮大。从早期的实验项目到今天的全球文化现象,电子游戏已经成为了娱乐的主要形式之一。它们的演变不仅受到技术的推动,还受到玩家社区的贡献和创新。

    电脑游戏的技术诞生

    电脑游戏的故事始于第二次世界大战后,当时世界各国投入巨大的资源来开发计算机技术,以协助战争努力。随着战争的结束,这些庞大的电子机器没有闲下来,而是成为了电脑游戏的诞生地。曼彻斯特大学、剑桥大学、宾夕法尼亚大学、普林斯顿大学等学术机构率先颁布了首个存储程序架构,为电脑重新编程提供了可能性。这一技术进步推动了雷明顿兰德公司、费兰提公司、IBM等机构在20世纪50年代初将电脑商业化,也促使大学、政府组织和大型公司开始采用电脑。正是在这种技术和学术氛围下,电脑游戏开始崭露头角。

    20世纪50年代的电脑游戏

    20世纪50年代的电脑游戏可以分为三类:培训和指导程序,人工智能领域的研究程序,以及旨在娱乐公众的示范程序。然而,这些游戏面临着独特的挑战,因为它们是为特定的硬件开发的,难以在不同系统之间移植。而且,由于当时的硬件资源有限,许多游戏在达到其目的后就被拆除或丢弃,因此它们并没有对整个游戏行业的发展产生直接影响。

    电脑游戏的早期亮点

    尽管电脑游戏的早期历史充满了挑战,但也有一些亮点。据已知,最早公开展示的电脑游戏之一是在1950年诞生的《大脑伯蒂》。这款游戏是井字棋的街机版本,由约瑟夫·凯特为加拿大博览会制作。他设计了一台专用电脑,用于展示自己设计的新型真空管。这台机器吸引了众多参观者,成为博览会的亮点之一。然而,这台电脑在博览会结束后就被拆除,成为了历史的一部分。

    Nimrod电脑和尼姆游戏

    在电脑游戏的发展中,英国的费兰提公司也有一席之地。他们制作了Nimrod电脑,这台电脑专门用于玩尼姆游戏。Nimrod电脑拥有巨大的尺寸,专门为游戏玩家设计,展示了电脑在娱乐方面的潜力。虽然最初的目的是展示电脑的设计和编程能力,但大多数参与者更感兴趣的是玩游戏。这台电脑在不列颠节和柏林工业展上展出后也被拆除,但它为电脑游戏的未来奠定了基础。

    电脑游戏的早期成就

    在电脑游戏的早期历史中,还有一些非视觉游戏的探索。克里斯托弗·斯特雷奇开发了模拟西洋跳棋的程序,成为已知首款为通用电脑创建的电脑游戏。此外,亚瑟·李·塞谬尔在IBM 701上开发了自己的西洋跳棋游戏,具备初步的人工智能能力。这些早期的努力为电脑游戏领域的未来打下了坚实的基础。

    井字棋的诞生

    在电子游戏的早期,计算机的用途主要分为三类:培训和指导程序、人工智能研究、以及娱乐示范程序。由于当时的计算机硬件各不相同,系统之间的移植极为困难,因此这些早期游戏主要是为了展示计算机的功能而制作,并没有影响到后来的游戏产业。

    电子游戏发展史:从早期探索到现代娱乐的演变 电子游戏发展史:从早期探索到现代娱乐的演变

    然而,已知最早的公开展示电子游戏可以追溯到1950年。这款游戏名为《大脑伯蒂》,是一款井字棋街机游戏,由约瑟夫·凯特为1950年加拿大博览会而制作。为了展示他设计的新型真空管,凯特制作了一台专用电脑,玩家可以在这台机器上与电脑对弈井字棋。这款游戏在博览会上大获成功,吸引了众多参观者。

    然而,这款游戏并没有长久存在,因为当时的电脑是为特定目的而制作的,游戏只是一个短暂的展示项目。不过,《大脑伯蒂》的诞生标志着电子游戏的开端,为后来的发展奠定了基础。

    井字棋到交互视觉游戏

    随着时间的推移,电子游戏逐渐发展壮大。在1952年,亚历山大·S·道格拉斯在延迟存储电子自动计算器上创建了井字棋游戏《OXO》。这台计算机是最早的存储程序电脑之一,具有可读写的内存,占据了整个房间。玩家可以使用拨号盘控制器输入他们的选择,然后电脑会进行回应,双方的走法都会在屏幕上显示出来。尽管这款游戏并没有对公众开放,只有获得剑桥大学特别许可的人才能够亲身体验,但它标志着电子游戏进一步的发展。

    在1950年代末,电子游戏逐渐演变成了交互视觉游戏。1958年,威廉·希金伯泰创建了一款网球模拟游戏《双人网球》。这是一款纯粹为了娱乐而设计的游戏,目的是在公众开放日为参观者提供更有趣的娱乐体验。玩家可以使用控制器控制击球角度,游戏会计算并模拟球的轨迹。这款游戏取得了巨大的成功,让更多人认识了电子游戏的娱乐价值。

    电子游戏发展史:从早期探索到现代娱乐的演变 电子游戏发展史:从早期探索到现代娱乐的演变

    此外,在1950年代末,各种电脑游戏继续在大学电脑和编程研究的背景下诞生。这些游戏不仅展示了电脑的运算能力,还为当时的计算机科学家和学生提供了娱乐方式。其中一些游戏包括井字棋和老鼠迷宫,它们是由本科生开发的,并在大学的电脑上运行。这些早期的尝试为电子游戏产业的崛起铺平了道路。

    早期大型计算机游戏的诞生

    电子游戏的历史可以追溯到20世纪50年代末和60年代初,当时大型计算机刚刚问世,它们的体积庞大、价格昂贵,只能在大学和研究机构中找到。这些庞大的机器往往被用于科学研究和数据处理,但一些创造性的程序员开始将它们用于娱乐目的。

    《太空战争!》:首款跨机构传播的游戏

    在1961年,麻省理工学院获得了数字设备公司生产的PDP-1小型计算机,这一机器在当时被认为是小型计算机的巅峰之作。PDP-1使用矢量显示系统,其处理速度和性能超越了之前的大型计算机,使其成为创新的平台。

    电子游戏发展史:从早期探索到现代娱乐的演变 电子游戏发展史:从早期探索到现代娱乐的演变

    在PDP-1上,员工史帝芬·罗素与马丁·格雷茨、韦恩·维塔宁等人合作开发了《太空战争!》,这是一款双人游戏,玩家在随机生成的星空背景下,操控宇宙飞船进行战斗。这款游戏的开发理念包括展示计算机的性能、保持游戏的多样性以及使游戏具有娱乐性。它在PDP-1上取得了巨大成功,并在其他PDP-1电脑上得以散播,成为首款跨机构传播的电子游戏。

    电子游戏的早期探索

    除了《太空战争!》之外,20世纪60年代后半期,高级编程语言(如BASIC)的出现进一步扩大了游戏的传播范围。这些游戏包括了棒球模拟、宾果、篮球模拟、棒球模拟和更多。其中,《星际旅行》因其在Multics操作系统上的开发,成为UNIX操作系统的催化剂,开启了新的计算机时代。

    电子游戏的崛起

    在早期大型计算机游戏的基础上,电子游戏开始迎来真正的崛起。20世纪70年代初,出现了第一批商业电子游戏,标志着游戏行业的诞生。

    第一批商业电子游戏

    1971年,Atari公司发布了第一款商业街机游戏《Pong》,这是一款模拟乒乓球比赛的游戏,引发了电子游戏行业的爆发。随着《Pong》的成功,电子游戏开始进入娱乐场所,成为人们娱乐的一部分。

    家用游戏机的兴起

    20世纪70年代末和80年代初,家用游戏机开始兴起。Atari的2600系列和任天堂的家用游戏机带给家庭娱乐一个全新的维度。这些游戏机推出了许多经典游戏,如《超级马里奥》和《坦克大战》,让更多人能够在家中享受电子游戏的乐趣。

    电子游戏发展史:从早期探索到现代娱乐的演变 电子游戏发展史:从早期探索到现代娱乐的演变

    电子游戏的普及

    随着个人计算机的普及,电子游戏的传播范围继续扩大。20世纪90年代,电子游戏开始进入个人计算机、游戏机和移动设备,玩家可以在各种平台上畅玩游戏。

    互联网时代的游戏

    随着互联网的发展,多人在线游戏(MMO)开始崭露头角。游戏如《魔兽世界》和《星际争霸》引领了互联网游戏的潮流,让玩家可以在全球范围内互相竞技和合作。

    电子游戏发展史:从早期探索到现代娱乐的演变 电子游戏发展史:从早期探索到现代娱乐的演变

    移动游戏的崛起

    21世纪初,智能手机的普及催生了移动游戏的热潮。游戏如《愤怒的小鸟》和《糖果粉碎传奇》成为全球范围内的现象级游戏,将电子游戏带入了数以亿计的手机用户的生活中。

    电子游戏发展史:从早期探索到现代娱乐的演变 电子游戏发展史:从早期探索到现代娱乐的演变

    街机电子游戏的崛起

    街机电子游戏的崛起源于之前由机电游戏机主导的街机游戏行业。1966年,世嘉推出了一款名为《潜望镜》的机电游戏机,它引领了一场由具备”视听”效果的新机电游戏机所推动的”技术复兴”。这一复兴为商业电子游戏的引入奠定了基础。

    而第一款商业街机电子游戏便是在1971年亮相的《电脑太空战》。这款游戏由诺兰·布什内尔和泰德·达布尼共同开发,灵感源自于1962年的游戏《太空战争!》。布什内尔曾在电子游戏厅工作,当他看到《太空战争!》后深信这款游戏的街机版本将会非常受欢迎。于是,他和达布尼着手开发这个游戏,并将它推向市场。

    然而,游戏开发并不是一帆风顺的。最初,他们计划使用诺瓦电脑作为游戏的基础,但很快遇到了技术上的困难。电脑的性能不够强大,无法同时运行多个游戏,而且刷新显示器的速度也无法满足游戏的要求。但他们并没有气馁,而是决定自行制作游戏机柜,并成功地推出了游戏原型。1971年8月,游戏原型在斯坦福大学附近的一家酒吧亮相,并获得了巨大成功。游戏备受欢迎,促使布什内尔与纳廷联合合作生产游戏机柜,正式推向市场,这标志着商业电子游戏的诞生。

    另一款早期街机电子游戏:《银河游戏》

    除了《电脑太空战》,另一款早期投币式街机电子游戏是1971年的《银河游戏》。这款游戏由比尔·皮茨和休·塔克开发,利用具备矢量显示器的PDP-11小型计算机。他们受到1962年的游戏《太空战争!》启发,认为投币版本将会取得成功。然而,游戏的成本很高,无法投入生产,最终未能实现商业化。

    电子游戏发展史:从早期探索到现代娱乐的演变 电子游戏发展史:从早期探索到现代娱乐的演变

    家用电子游戏机的崛起

    1972年,电子游戏行业迎来了另一个重要事件:首款可以连接至电视机的家用电子游戏机——米罗华奥德赛的发行。这个家用游戏机由工程师拉夫·亨利·贝尔发明,他早在1951年就萌生了在电视机上制作交互游戏的想法,但当时的技术无法实现。经过多年的努力,他终于在1972年将奥德赛推向市场,它成为了首款面向家庭消费者的电子游戏设备。

    奥德赛的成功在一定程度上归功于流行的乒乓球运动,因为游戏中包括了乒乓球游戏。这款游戏机定价合理,销量迅速突破十万台,为家用电子游戏机的兴起打下了基础。

    结语

    20世纪70年代初,电子游戏行业经历了巨大的变革,商业电子游戏开始崭露头角。街机电子游戏和家用电子游戏机的崛起为电子游戏产业的发展开辟了新的道路,成为电子游戏史上的重要里程碑。

    这个时代的重要事件和创新为电子游戏的未来奠定了坚实的基础,也启示我们,不论是技术的进步还是创意的迸发,都能够推动一个行业的蓬勃发展。

  • 如何应对小米手机突然无法开机的问题

    如何应对小米手机突然无法开机的问题

    曾经的一天早晨,王大神的手机突然出现了无法开机的问题,这让他感到非常困扰。如果你也曾遇到过类似的情况,那么请继续阅读,因为本文将为你解答可能导致手机无法开机的原因以及如何应对这一问题。

    问题背景

    在故事中,王大神使用的是一款红米 K40 手机,一直以来都表现得非常稳定可靠。然而,最近他遇到了一个问题,手机在一晚上的充电后,突然无法正常开机。让我们一起来分析可能的原因以及解决方法。

    问题原因

    在这种情况下,有几个可能导致手机无法开机的原因:

    1. 硬件问题:可能存在硬件故障,比如CPU虚焊或其他主板问题。这些问题可能会导致手机无法正常启动。

    2. 充电方式:王大神提到他习惯将手机电量耗尽后再充电。这种方式可能对电池健康造成影响,尤其是在长时间内频繁使用类似的充电方式。

    解决方法

    既然我们了解了可能的原因,现在让我们看看如何应对这一问题:

    1. 备份数据:首先,无论出现什么问题,一定要确保手机中重要的数据已经备份。这可以通过连接到电脑或使用云存储服务来完成。

    2. 检查硬件:如果可能的原因是硬件问题,建议寻求专业技术支持。检查CPU虚焊或其他主板问题是否存在,并及时修复。

    3. 调整充电方式:对于充电方式,建议不要频繁将手机电量耗尽后再充电,因为这可能对电池健康不利。尽量保持电池在30%到80%之间,以延长电池寿命。

    4. 系统更新:确保手机上安装了最新的系统更新。有时,问题可能是由于操作系统的一个bug引起的,而更新可以修复这些问题。

    5. 联系厂家:如果问题无法解决,不要犹豫与手机制造商或官方客服联系,寻求他们的帮助和建议。

    结论

    王大神的手机问题最终得以解决,但这个过程也让他明白了手机维护的重要性。保持手机硬件的健康,适当调整充电方式,及时备份数据,都是保持手机顺利运行的关键。

    如果你的手机也遇到类似的问题,不要惊慌,尝试按照上述方法来解决。如果问题持续存在,记得随时联系专业技术支持,他们将能够为你提供更具体的帮助。

    希望这篇文章对你有所帮助,祝愿你的手机能够一直保持良好的状态!