强制某些代码始终在同一线程上运行

2023-12-08

我们有一个旧的第 3 方系统(我们称之为 Junksoft® 95),我们通过 PowerShell 与之交互(它公开 COM 对象),我正在将其包装在 REST API(ASP.NET Framework 4.8 和 WebAPI)中2)。我用System.Management.Automationnuget 包来创建PowerShell其中我将 Junksoft 的 COM API 实例化为dynamic然后我使用的对象:

//I'm omitting some exception handling and maintenance code for brevity
powerShell = System.Management.Automation.PowerShell.Create();
powerShell.AddScript("Add-Type -Path C:\Path\To\Junksoft\Scripting.dll");
powerShell.AddScript("New-Object Com.Junksoft.Scripting.ScriptingObject");
dynamic junksoftAPI = powerShell.Invoke()[0];

//Now we issue commands to junksoftAPI like this:
junksoftAPI.Login(user,pass);
int age = junksoftAPI.GetAgeByCustomerId(custId);
List<string> names = junksoftAPI.GetNames();

当我在同一线程上运行所有这些时(例如在控制台应用程序中),这工作得很好。然而,由于某种原因,这usually当我放置时不起作用junksoftAPI into a System.Web.Caching.Cache并从我的网络应用程序中的不同控制器使用它。我说ususally因为当 ASP.NET 碰巧向线程发出传入调用时,这实际上起作用junksoftAPI创建于。如果没有,Junksoft 95 会给我一个错误。

我有什么办法可以确保与junksoftAPI发生在same thread?

Note我不想将整个 Web 应用程序变成单线程应用程序!控制器和其他地方的逻辑应该像正常情况一样在不同的线程上发生。它应该只是在 Junksoft 特定线程上发生的 Junksoft 交互,如下所示:

[HttpGet]
public IHttpActionResult GetAge(...)
{
    //finding customer ID in database...

    ...

    int custAge = await Task.Run(() => {
        //this should happen on the Junksoft-specific thread and not the next available thread
        var cache = new System.Web.Caching.Cache();
        var junksoftAPI = cache.Get(...); //This has previously been added to cache on the Junksoft-specific thread
        return junksoftAPI.GetAgeByCustomerId(custId);
    });

    //prepare a response using custAge...
}

您可以创建自己的单例工作线程来实现此目的。以下是您可以将其插入到您的 Web 应用程序中的代码。

public class JunkSoftRunner
{
    private static JunkSoftRunner _instance;

    //singleton pattern to restrict all the actions to be executed on a single thread only.
    public static JunkSoftRunner Instance => _instance ?? (_instance = new JunkSoftRunner());

    private readonly SemaphoreSlim _semaphore;
    private readonly AutoResetEvent _newTaskRunSignal;

    private TaskCompletionSource<object> _taskCompletionSource;
    private Func<object> _func;

    private JunkSoftRunner()
    {
        _semaphore = new SemaphoreSlim(1, 1);
        _newTaskRunSignal = new AutoResetEvent(false);
        var contextThread = new Thread(ThreadLooper)
        {
            Priority = ThreadPriority.Highest
        };
        contextThread.Start();
    }

    private void ThreadLooper()
    {
        while (true)
        {
            //wait till the next task signal is received.
            _newTaskRunSignal.WaitOne();

            //next task execution signal is received.
            try
            {
                //try execute the task and get the result
                var result = _func.Invoke();

                //task executed successfully, set the result
                _taskCompletionSource.SetResult(result);
            }
            catch (Exception ex)
            {
                //task execution threw an exception, set the exception and continue with the looper
                _taskCompletionSource.SetException(ex);
            }

        }
    }

    public async Task<TResult> Run<TResult>(Func<TResult> func, CancellationToken cancellationToken = default(CancellationToken))
    {
        //allows only one thread to run at a time.
        await _semaphore.WaitAsync(cancellationToken);

        //thread has acquired the semaphore and entered
        try
        {
            //create new task completion source to wait for func to get executed on the context thread
            _taskCompletionSource = new TaskCompletionSource<object>();

            //set the function to be executed by the context thread
            _func = () => func();

            //signal the waiting context thread that it is time to execute the task
            _newTaskRunSignal.Set();

            //wait and return the result till the task execution is finished on the context/looper thread.
            return (TResult)await _taskCompletionSource.Task;
        }
        finally
        {
            //release the semaphore to allow other threads to acquire it.
            _semaphore.Release();
        }
    }
}

控制台主要测试方法:

public class Program
{
    //testing the junk soft runner
    public static void Main()
    {
        //get the singleton instance
        var softRunner = JunkSoftRunner.Instance;

        //simulate web request on different threads
        for (var i = 0; i < 10; i++)
        {
            var taskIndex = i;
            //launch a web request on a new thread.
            Task.Run(async () =>
            {
                Console.WriteLine($"Task{taskIndex} (ThreadID:'{Thread.CurrentThread.ManagedThreadId})' Launched");
                return await softRunner.Run(() =>
                {
                    Console.WriteLine($"->Task{taskIndex} Completed On '{Thread.CurrentThread.ManagedThreadId}' thread.");
                    return taskIndex;
                });
            });
        }
    }   
}

Output:

enter image description here

请注意,虽然该函数是从不同的线程启动的,但代码的某些部分始终在 ID 为“5”的同一上下文线程上执行。

但请注意,尽管所有 Web 请求都在独立线程上执行,但它们最终将等待某些任务在单例工作线程上执行。这最终会在您的 Web 应用程序中造成瓶颈。无论如何,这都是你的设计限制。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

强制某些代码始终在同一线程上运行 的相关文章

  • 我怎么知道PowerShell函数参数被省略了

    考虑这样的函数 function Test foo bar 我们可以称之为 Test foo null Test 我如何知道何时省略了 foo 以及何时为 null 如果您使用的是 Powershell V2 或更高版本 则可以使用 PSB
  • 用于检查项目文件中的项目变量和引用路径的 api

    我正在研究一个 net application VS2010 与 x 没有 解和变量号这些解决方案中的项目数量 我需要检查项目属性 特定于一定数量的项目 是否同质 并且检查 验证构建期间的参考路径 有没有一个API是这样的吗 如果没有 我该
  • 获取 WPF 控件的所有附加事件处理程序

    我正在开发一个应用程序 在其中动态分配按钮的事件 现在的问题是 我希望获取按钮单击事件的所有事件 因为我希望删除以前的处理程序 我尝试将事件处理程序设置为 null 如下所示 Button Click null 但是我收到了一个无法分配 n
  • 回发或回调参数无效。使用“”启用事件验证

    当我从客户端回发页面时 出现以下错误 我有修改客户端 asp ListBox 的 JavaScript 代码 我们该如何解决这个问题 错误详细信息如下 Server Error in XXX Application Invalid post
  • 验证插件在更新面板中不起作用

    我有一个更新面板 面板内有文本框和按钮可用 现在我正在使用 jQuery Validation 插件 但是在更新面板中使用时验证插件不起作用 例如 function GetAddressTargetList var objArray new
  • PyCharm - 如何挂起所有线程

    我们使用 PyCharm 5 0 1 进行多线程调试 当它在断点处停止时 只有特定线程停止 而所有其他线程继续 这使得 冻结时刻 和检查参数值以及其他线程的当前状态变得困难 当其中一个线程在断点处停止时 是否可以挂起所有线程 这在最新的 P
  • PlaySound 可在 Visual Studio 中运行,但不能在独立 exe 中运行

    我正在尝试使用 Visual Studio 在 C 中播放 wav 文件 我将文件 my wav 放入项目目录中并使用代码 PlaySound TEXT my wav NULL SND FILENAME SND SYNC 我按下播放按钮 或
  • 加密和解密图像.net

    谁能给我一个使用 net 和 asp net 加密和解密图像的示例 当我将图像作为二进制数据保存到 SQL Server 中时 我希望对图像进行加密 包含这些名称空间 using System IO using System Securit
  • 上下文敏感与歧义

    我对上下文敏感性和歧义如何相互影响感到困惑 我认为正确的是 歧义 歧义语法会导致使用左推导或右推导构建多个解析树 所有可能的语法都是二义性的语言是二义性语言 例如 C 是一种不明确的语言 因为 x y 总是可以表示两个不同的事物 如下所述
  • 无需安装即可部署 Expression Encoder SDK

    我试图在使用 Microsoft Expression Encoder 3 SDK 时证明一个概念 我正在尝试将 SDK 部署到我的托管 Web 服务器 以了解更多关于它是否有效以及还需要安装什么的信息 我无法在服务器上进行任何操作 以下是
  • 如何编写一个同时需要请求和响应Dtos的ServiceStack插件

    我需要提供本地化数据服务 所有本地化的响应 Dto 都共享相同的属性 IE 我定义了一个接口 ILocalizedDto 来标记那些 Dto 在请求端 有一个ILocalizedRequest对于需要本地化的请求 Using IPlugin
  • HttpWebRequest 在第二次调用时超时

    为什么以下代码在第二次 及后续 运行时超时 代码挂在 using Stream objStream request GetResponse GetResponseStream 然后引发 WebException 表示请求已超时 我已经尝试过
  • 如何从main方法调用业务对象类?

    我已将代码分为业务对象 访问层 如下所示 void Main Business object public class ExpenseBO public void MakeExpense ExpensePayload payload var
  • .NET中的LinkedList是循环链表吗?

    我需要一个循环链表 所以我想知道是否LinkedList是循环链表吗 每当您想要移动列表中的 下一个 块时 以循环方式使用它的快速解决方案 current current Next current List First 电流在哪里Linke
  • 用于 C# 的 TripleDES IV?

    所以当我说这样的话 TripleDES tripledes TripleDES Create Rfc2898DeriveBytes pdb new Rfc2898DeriveBytes password plain tripledes Ke
  • 如果方法参数是 string 或 int,ASP.NET WebAPI 会抛出 404

    我对 ASP NET MVC4 WebAPI 做了一个非常简单的测试 发现了一些有趣的问题 当一个方法采用复杂类型时 它会起作用 但是当它采用 string 或 int 时 它将抛出 404 如给出的屏幕截图所示 AddProduct 可以
  • Process.Start() 方法在什么情况下返回 false?

    From MSDN https msdn microsoft com en us library e8zac0ca v vs 110 aspx 返回值 true 表示有新的进程资源 开始了 如果由 FileName 成员指定的进程资源 St
  • 有没有办法强制显示工具提示?

    我有一个验证字段的方法 如果无法验证 该字段将被清除并标记为红色 我还希望在框上方弹出一个工具提示 并向用户显示该值无效的消息 有没有办法做到这一点 并且可以控制工具提示显示的时间 我怎样才能让它自己弹出而不是鼠标悬停时弹出 If the
  • 英特尔 Pin 与 C++14

    问题 我有一些关于在 C 14 或其他 C 版本中使用英特尔 Pin 的问题 使用较新版本从较旧的 C 编译代码很少会出现任何问题 但由于 Intel Pin 是操作指令级别的 如果我使用 C 11 或 C 14 编译它 是否会出现任何不良
  • 防止在工厂方法之外实例化对象

    假设我有一个带有工厂方法的类 class A public static A newA Some code logging return new A 是否可以使用 a 来阻止此类对象的实例化new 那么工厂方法是创建对象实例的唯一方法吗 当

随机推荐

  • 如何根据日期删除多个间隔分区?

    我有一个基于每日分区的表 我可以使用以下查询删除分区 ALTER TABLE MY TABLE DROP PARTITION FOR TO DATE 19 DEC 2017 dd MON yyyy 如何在15天内删除所有分区 多个分区 您可
  • 在 Tkinter.Tcl() 中使用 Python 函数

    我有很多 Python 函数 让我们称呼他们为foo bar and baz 它们接受可变数量的字符串参数并执行其他复杂的操作 例如访问网络 我希望 用户 假设他只熟悉 Tcl 使用这些函数在 Tcl 中编写脚本 这是一个例子 取自Macp
  • 如何在以句点结尾的注释行后禁用 RubyMine 代码完成?

    我正在使用 RubyMine 6 3 2 当我输入以下行并按回车键时 This is a comment 编辑器插入附加文本 结果是 This is a comment after do end 我知道发生这种情况是因为 aft 是输入 后
  • R 图中的文本无法正确显示

    我的 R 安装在 Ubuntu 20 04 1 VM 上的 conda 环境中 当我发现这个线程时 我正在寻找这个问题 我也在 Debian 10 0 buster 上使用 Anaconda 的 RStudio Try par family
  • 如果 :target 不存在,如何为元素设置默认样式

    我有一个带有 3 个链接的标题 所有链接都链接到具有相应 id 的特定 div body font size 32px links display flex a padding 10px box not target display non
  • 如何将编辑项添加到 TFS 工作项中的预定义列表

    I am trying to follow this article to do the same for adding a new State to a particular project s Bug work item By defa
  • jQuery:如何包装()动态加载的元素?

    我正在为一个本身没有 HTML 的第 3 方应用程序进行换皮 这一切都来自 onLoad 事件和一堆 ajax 调用 我将 jQuery 添加到页面中 我需要wrapp 一个动态加载的元素 如果需要的话我可以添加一个插件 我该怎么做呢 谢谢
  • 绑定 this 后 setState 不是一个函数

    我有一个简单的表单 允许用户创建纯文本帖子 下面的代码生成一个成功的服务器端响应createPostRequest称呼 但是 在成功发布后 我想更新状态以清空 postBody 字段并更新 UI 以反映此更改 然后允许用户发出后续请求以发布
  • 构建工具更新破坏了我的编译

    我今天早上4点到5点更新了Android Studio 2 0 Preview 如果我继续构建 dependencies classpath com android tools build gradle 2 0 0 alpha3 这仍然会编
  • 在java中,如何从jar文件中检索图像?

    我在将 java 项目导出到 jar 从 Eclipse 时遇到问题 我已将一个文件包含在名为的 jar 中images 它包含我的项目使用的所有图像文件 问题是 我对这些图像的引用仅在项目isn t罐子形式 我不明白为什么 我想知道是否需
  • 合并具有不同计数值的多个文件

    我想通过从每个文件中取出第二列来合并 96 个文件 并保留所有文件之间相似的第一列 我尝试在 R 中执行此操作 但认为在终端中会更好 使用awk可以吗 样本数据 DMED7013 Rfam robinm head Rfam Counts c
  • Entity Framework Core 2.1 无法正确转换查询

    我有一个现有数据库 我从 2 个独立的项目访问该数据库 其中一个是 ASP NET MVC 5 项目 另一个使用每个项目中各自的实体框架版本运行 NET Core 2 1 我的问题是 我在 MVC 项目上使用的查询在 NET Core 项目
  • Linkedin OAuth2 授权码错误

    我正在尝试通过 Linkedin Auth2 从 Java Web 应用程序进行连接 在 linkedin 中添加了我自己的应用程序 生成授权URL 在新的弹出窗口中输入我的 linkedin 登录名 密码 在redirect uri上返回
  • 继承接口的Java重载方法

    我正在尝试了解java行为 使用此接口 public interface IA public interface IB extends IA public class myClass implements IB 我正在重载这样的方法 pub
  • 使用 JAXB 映射包含超类型和子类型的 Java 集合

    我正在尝试用 JAXB 制作这样的东西
  • 使函数在完成一些工作后返回自身

    let log x print int x log log 111 222 我期待着log打印111并返回自身然后打印222在第二次调用时 但它没有按预期工作 而是收到一条错误消息 为什么 如何让它按预期工作 我也尝试过rec无济于事 Fi
  • 超出 C# 中基本类型的数字

    我正在解决问题欧拉计划 大部分问题都解决了 超过 ulong 的大数字 Ex ulong number 81237146123746237846293567465365862854736263874623654728568263582 有效
  • 仍在努力处理大数据集

    我一直在这个网站上阅读 但未能找到确切的答案 如果它已经存在 我对重新发布表示歉意 我正在处理非常大的数据集 在具有 32 GB RAM 的计算机上有 6 亿行 64 列 我实际上只需要这些数据的更小的子集 但除了简单地使用 fread 导
  • 审计日志记录nhibernate

    您能否提供一些使用 NHibernate 进行审计日志记录的示例 ASP Net C 代码 而不是 java 代码 事件监听器比拦截器更适合审计信息 这是一个很好的例子 from 阿延德的博客
  • 强制某些代码始终在同一线程上运行

    我们有一个旧的第 3 方系统 我们称之为 Junksoft 95 我们通过 PowerShell 与之交互 它公开 COM 对象 我正在将其包装在 REST API ASP NET Framework 4 8 和 WebAPI 中2 我用S